1 /* JChessBoard -- a chess game 2 * Copyright (C) 2000-2004 Claus Divossen <claus.divossen@gmx.de> 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 17 */ 18 19 /* $Id: Protocol.java,v 1.6 2004/12/26 23:12:14 cdivossen Exp $ */ 20 21 package jchessboard; 22 23 import java.util.StringTokenizer; 24 25 import javax.swing.JOptionPane; 26 27 /** 28 * @author cd 29 * 30 * To change the template for this generated type comment go to 31 * Window>Preferences>Java>Code Generation>Code and Comments 32 */ 33 public class Protocol { 34 public final static String MOVE_MESSAGE = "move"; 35 public final static String BATCH_MOVE_MESSAGE = "batch_move"; 36 public final static String BATCH_FINISHED_MESSAGE = "batch_finished"; 37 public final static String BATCH_CANCELED_MESSAGE = "batch_canceled"; 38 public final static String START_UPLOAD_MESSAGE = "start_upload"; 39 public final static String NEW_GAME_MESSAGE = "new_game"; 40 public final static String REQUEST_NEW_GAME_MESSAGE = "request_new"; 41 public final static String NEW_GAME_REJECTED_MESSAGE = "new_rejected"; 42 public final static String UNDO_MESSAGE = "undo"; 43 public final static String UNDO_REJECTED_MESSAGE = "undo_rejected"; 44 public final static String GAME_TIME_MESSAGE = "gametime"; 45 public final static String PLAYERS_TIME_MESSAGE = "playerstime"; 46 public final static String REQUEST_UNDO_MESSAGE = "request_undo"; 47 public final static String REQUEST_CLOCK_CHANGE_MESSAGE = "request_clock_change"; 48 public final static String CLOCK_CHANGE_REJECTED_MESSAGE = "clock_change_rejected"; 49 public final static String REQUEST_TOGGLE_CLOCK_MESSAGE = "request_enable_clock"; 50 public final static String REJECT_TOGGLE_CLOCK_MESSAGE = "reject_enable_clock"; 51 public final static String ACCEPT_TOGGLE_CLOCK_MESSAGE = "accept_enable_clock"; 52 public final static String REQUEST_DISABLE_CLOCK_MESSAGE = "request_disable_clock"; 53 public final static String REJECT_DISABLE_CLOCK_MESSAGE = "reject_disable_clock"; 54 public final static String ACCEPT_DISABLE_CLOCK_MESSAGE = "accept_disable_clock"; 55 public final static String OFFER_DRAW_MESSAGE = "offer_draw"; 56 public final static String DRAW_ACCEPTED_MESSAGE = "draw_accepted"; 57 public final static String DRAW_REJECTED_MESSAGE = "draw_rejected"; 58 public final static String REQUEST_SIDE_SWITCH_MESSAGE = "request_side_switch"; 59 public final static String SIDE_SWITCH_ACCEPTED_MESSAGE = "side_switch_accepted"; 60 public final static String SIDE_SWITCH_REJECTED_MESSAGE = "side_switch_rejected"; 61 public final static String REQUEST_UPLOAD_MESSAGE = "request_upload"; 62 public final static String REJECT_UPLOAD_MESSAGE = "reject_upload"; 63 public final static String ACCEPT_UPLOAD_MESSAGE = "accept_upload"; 64 public final static String RESIGNED_MESSAGE = "resign"; 65 public final static String USER_MESSAGE = "message"; 66 public final static String RESTART_MESSAGE = "restart"; 67 public final static String QUIT_MESSAGE = "quit"; 68 public final static String WELCOME_MESSAGE = "Welcome!"; 69 public final static String REJECTED_MESSAGE = "Go away!"; 70 public final static String INIT_FROM_FEN_MESSAGE = "init_from_fen"; 71 public final static String ERROR_MESSAGE = "error"; 72 public final static String PLAYER_NAME_MESSAGE = "playername"; 73 74 protected java.util.LinkedList pendingAcks = new java.util.LinkedList(); 75 protected boolean gameIsLoading = false; 76 protected boolean protocolIsConnected = false; 77 protected boolean protocolServer = false; 78 private JChessBoard jcb; // The parent JChessBoard 79 // private BoardConnector boardConnector; 80 private String otherPlayersName = "Opponent"; 81 isConnected()82 public boolean isConnected() { 83 return protocolIsConnected; 84 } 85 clearPendingAcks()86 public void clearPendingAcks() { 87 pendingAcks.clear(); 88 } 89 sendWelcome()90 public void sendWelcome() { 91 sendMessage(WELCOME_MESSAGE); 92 } 93 connectionClosed()94 public void connectionClosed() { 95 protocolIsConnected = false; 96 protocolServer = false; 97 pendingAcks.clear(); 98 } 99 connectionEstablished()100 public void connectionEstablished() { 101 protocolIsConnected = true; 102 clearPendingAcks(); 103 } 104 connecting()105 public void connecting() { 106 protocolServer = false; 107 protocolIsConnected = false; 108 } 109 sendMove(Move move)110 public void sendMove(Move move) { 111 sendMessage(MOVE_MESSAGE, move.toString()); 112 } 113 sendBatchMove(Move move)114 public void sendBatchMove(Move move) { 115 sendMessage(BATCH_MOVE_MESSAGE, move.toString()); 116 } 117 startUpload()118 public void startUpload() { 119 sendMessage(START_UPLOAD_MESSAGE); 120 } 121 uploadDone()122 public void uploadDone() { 123 sendMessage(BATCH_FINISHED_MESSAGE); 124 } 125 requestNewGame()126 public void requestNewGame() { 127 sendMessage(REQUEST_NEW_GAME_MESSAGE); 128 } 129 offerDraw()130 public void offerDraw() { 131 sendMessage(OFFER_DRAW_MESSAGE); 132 } 133 resigned()134 public void resigned() { 135 sendMessage(RESIGNED_MESSAGE); 136 } 137 requestSideSwitch()138 public void requestSideSwitch() { 139 sendMessage(REQUEST_SIDE_SWITCH_MESSAGE); 140 } 141 requestToggleClock()142 public void requestToggleClock() { 143 sendMessage(REQUEST_TOGGLE_CLOCK_MESSAGE); 144 } 145 sendPlayersTime(long playersTime)146 public void sendPlayersTime(long playersTime) { 147 sendMessage(PLAYERS_TIME_MESSAGE, "" + playersTime); 148 } 149 sendError(String message)150 public void sendError(String message) { 151 sendMessage(ERROR_MESSAGE, message); 152 } 153 requestClockChange(long newWhiteTime, long newBlackTime)154 public void requestClockChange(long newWhiteTime, long newBlackTime) { 155 sendMessage(REQUEST_CLOCK_CHANGE_MESSAGE, "" + newWhiteTime + " " + newBlackTime); 156 } 157 requestUndo()158 public void requestUndo() { 159 sendMessage(REQUEST_UNDO_MESSAGE); 160 } 161 requestUpload()162 public void requestUpload() { 163 sendMessage(REQUEST_UPLOAD_MESSAGE); 164 } 165 initFromFEN(String fen)166 public void initFromFEN(String fen) { 167 sendMessage(INIT_FROM_FEN_MESSAGE, fen); 168 } 169 sendPlayerName(String name)170 public void sendPlayerName(String name) { 171 sendMessage(PLAYER_NAME_MESSAGE,name); 172 } 173 174 /** 175 * Handles all the messages from a connected board. The heart of the 176 * protocol; it must handle all the incoming commands, as well as receive 177 * and send acknowledgements. 178 * 179 * @param line A line of input retrieved from the connected board. 180 */ handleInput(String line)181 public void handleInput(String line) { 182 StringTokenizer st; 183 String message = null; 184 String value = null; 185 String value2 = null; 186 187 // Pull the first three words out of the line: message, value, value2 188 st = new StringTokenizer(line); 189 if (st.hasMoreTokens()) 190 message = st.nextToken(); 191 if (st.hasMoreTokens()) 192 value = st.nextToken(); 193 if (st.hasMoreTokens()) 194 value2 = st.nextToken(); 195 196 // That first token tells us what to do 197 if (message != null) { 198 if (message.equals(QUIT_MESSAGE)) { 199 jcb.showMessage("Opponent has quit!"); 200 jcb.boardConnector.closeConnection(); 201 jcb.connectionClosed(); 202 } 203 // Checking the answers: 204 else if (message.equals("?")) // Peer didn't understand. 205 { 206 // Reset communications 207 jcb.showMessage("Out of sync! Trying to restart..."); 208 jcb.boardConnector.sendString(RESTART_MESSAGE); 209 pendingAcks.clear(); 210 jcb.connectionIndicator.setError(); 211 } else if (message.equals("OK " + RESTART_MESSAGE)) { 212 jcb.newGame(); 213 jcb.connectionIndicator.setReady(); 214 jcb.showMessage("Restarted due to unkown error."); 215 jcb.beep(); 216 } else if (message.equals("OK") && value != null && pendingAcks.size() > 0) { 217 // Our latest message was received 218 if (line.equals("OK " + (String) pendingAcks.get(0))) { 219 pendingAcks.remove(0); 220 if (pendingAcks.size() == 0) { 221 jcb.connectionIndicator.setReady(); 222 } 223 } 224 } else { 225 // Got new command from peer 226 if (message.equals(WELCOME_MESSAGE)) { 227 // Only clients get this message. 228 // We're connected and ready to go 229 acknowledge(line); 230 protocolIsConnected = true; 231 jcb.connectionIndicator.setReady(); 232 jcb.showMessage("Game accepted."); 233 jcb.connectionEstablished(); 234 } else if (message.equals(REJECTED_MESSAGE)) { 235 // We've been rejected 236 jcb.beep(); 237 jcb.showMessage("Other player doesn't want to play."); 238 jcb.connectionClosed(); 239 } else if (message.equals(UNDO_MESSAGE)) { 240 // Undo handling 241 jcb.undoMove(); 242 jcb.beep(); 243 acknowledge(line); 244 } else if (message.equals(REQUEST_UNDO_MESSAGE)) { 245 Object[] options = { "Accept", "Reject" }; 246 int selection = 247 JOptionPane.showOptionDialog( 248 null, 249 "Opponent wants to take back the last move.", 250 "Undo request", 251 JOptionPane.YES_NO_OPTION, 252 JOptionPane.QUESTION_MESSAGE, 253 null, 254 options, 255 options[0]); 256 acknowledge(line); 257 if (selection == JOptionPane.YES_OPTION) { 258 jcb.undoMove(); 259 sendMessage(UNDO_MESSAGE); 260 } else { 261 sendMessage(UNDO_REJECTED_MESSAGE); 262 } 263 } else if (message.equals(UNDO_REJECTED_MESSAGE)) { 264 jcb.showMessage("Undo request rejected."); 265 acknowledge(line); 266 } else if (message.equals(REQUEST_TOGGLE_CLOCK_MESSAGE)) { 267 // Enabling the clock 268 Object[] options = { "Accept", "Reject" }; 269 int selection = 270 JOptionPane.showOptionDialog( 271 null, 272 "Opponent wants to turn " + (jcb.getEnableClock() ? "off" : "on") + " the clock", 273 "Clock request", 274 JOptionPane.YES_NO_OPTION, 275 JOptionPane.QUESTION_MESSAGE, 276 null, 277 options, 278 options[0]); 279 acknowledge(line); 280 if (selection == JOptionPane.YES_OPTION) { 281 jcb.setEnableClock(!jcb.getEnableClock()); 282 jcb.update(); 283 jcb.showMessage("Chess clocks " + (jcb.getEnableClock() ? "enabled" : "disabled") + "."); 284 sendMessage(ACCEPT_TOGGLE_CLOCK_MESSAGE); 285 } else { 286 sendMessage(REJECT_TOGGLE_CLOCK_MESSAGE); 287 } 288 } else if (message.equals(ACCEPT_TOGGLE_CLOCK_MESSAGE)) { 289 jcb.setEnableClock(!jcb.getEnableClock()); 290 // jcb.setEnableClock(false); 291 jcb.update(); 292 jcb.showMessage("Chess clocks " + (jcb.getEnableClock() ? "enabled" : "disabled") + "."); 293 acknowledge(line); 294 } else if (message.equals(REJECT_TOGGLE_CLOCK_MESSAGE)) { 295 jcb.showMessage( 296 "Your wish to turn " + (jcb.getEnableClock() ? "off" : "on") + " the clock was rejected."); 297 acknowledge(line); 298 } 299 // Draw handling 300 else if (message.equals(OFFER_DRAW_MESSAGE)) { 301 Object[] options = { "Accept", "Reject" }; 302 int selection = 303 JOptionPane.showOptionDialog( 304 null, 305 "Opponent offers a draw.", 306 "Draw offered", 307 JOptionPane.YES_NO_OPTION, 308 JOptionPane.QUESTION_MESSAGE, 309 null, 310 options, 311 options[0]); 312 acknowledge(line); 313 if (selection == JOptionPane.YES_OPTION) { 314 sendMessage(DRAW_ACCEPTED_MESSAGE); 315 jcb.showMessage("Draw accepted."); 316 // jcb.stopGame(); 317 jcb.history.setResult("1/2-1/2"); 318 } else { 319 sendMessage(DRAW_REJECTED_MESSAGE); 320 } 321 } else if (message.equals(DRAW_ACCEPTED_MESSAGE)) { 322 jcb.showMessage("Draw accepted."); 323 jcb.beep(); 324 // jcb.stopGame(); 325 jcb.history.setResult("1/2-1/2"); 326 acknowledge(line); 327 } else if (message.equals(DRAW_REJECTED_MESSAGE)) { 328 jcb.showMessage("Draw rejected."); 329 acknowledge(line); 330 } 331 // Resign 332 else if (message.equals(RESIGNED_MESSAGE)) { 333 acknowledge(line); 334 jcb.showMessage("Opponent resigned."); 335 jcb.beep(); 336 // jcb.stopGame(); 337 jcb.history.setResult((jcb.whitePlayer == JChessBoard.HUMAN) ? "1-0" : "0-1"); 338 } 339 // New Game 340 else if (message.equals(NEW_GAME_MESSAGE)) { 341 jcb.beep(); 342 jcb.history.clear(); 343 jcb.newGame(); 344 jcb.showMessage("New game."); 345 acknowledge(line); 346 } else if (message.equals(REQUEST_NEW_GAME_MESSAGE)) { 347 jcb.beep(); 348 Object[] options = { "Accept", "Reject" }; 349 int selection = 350 JOptionPane.showOptionDialog( 351 null, 352 "Opponent requests a new game.", 353 "New game?", 354 JOptionPane.YES_NO_OPTION, 355 JOptionPane.QUESTION_MESSAGE, 356 null, 357 options, 358 options[0]); 359 acknowledge(line); 360 if (selection == JOptionPane.YES_OPTION) { 361 jcb.history.clear(); 362 jcb.newGame(); 363 jcb.showMessage("New game."); 364 sendMessage(NEW_GAME_MESSAGE); 365 } else { 366 sendMessage(NEW_GAME_REJECTED_MESSAGE); 367 } 368 } else if (message.equals(NEW_GAME_REJECTED_MESSAGE)) { 369 jcb.showMessage("New game rejected."); 370 acknowledge(line); 371 } 372 // Time handling 373 else if (message.equals(REQUEST_CLOCK_CHANGE_MESSAGE)) { 374 long newWhiteTime = Long.parseLong(value); 375 long newBlackTime = Long.parseLong(value2); 376 Object[] options = { "Accept", "Reject" }; 377 int selection = 378 JOptionPane.showOptionDialog( 379 null, 380 "Opponent wants to change the clocks to:\n " 381 + "White: " 382 + jcb.chessClock.formatTime(newWhiteTime) 383 + " Black: " 384 + jcb.chessClock.formatTime(newBlackTime), 385 "Change clocks?", 386 JOptionPane.YES_NO_OPTION, 387 JOptionPane.QUESTION_MESSAGE, 388 null, 389 options, 390 options[0]); 391 acknowledge(line); 392 if (selection == JOptionPane.YES_OPTION) { 393 sendMessage(GAME_TIME_MESSAGE, "" + newWhiteTime + " " + newBlackTime); 394 jcb.setClocks(newWhiteTime, newBlackTime); 395 } else { 396 sendString(CLOCK_CHANGE_REJECTED_MESSAGE); 397 } 398 } else if (message.equals(CLOCK_CHANGE_REJECTED_MESSAGE)) { 399 jcb.showMessage("Clock change rejected."); 400 acknowledge(line); 401 } else if (message.equals(GAME_TIME_MESSAGE) && value != null && value2 != null) { 402 jcb.setClocks(Long.parseLong(value), Long.parseLong(value2)); 403 acknowledge(line); 404 } else if (message.equals(PLAYERS_TIME_MESSAGE) && value != null) { 405 // Required to synchronize the clocks. 406 if (jcb.blackPlayer == JChessBoard.PEER) { 407 long time = Long.parseLong(value); 408 jcb.chessClock.setBlackPlayersTime(time); 409 jcb.checkFinish(); 410 } else if (jcb.whitePlayer == JChessBoard.PEER) { 411 long time = Long.parseLong(value); 412 jcb.chessClock.setWhitePlayersTime(time); 413 jcb.checkFinish(); 414 } 415 acknowledge(line); 416 // Restart 417 } else if (message.equals(RESTART_MESSAGE)) { 418 // The other board must have detected an error. 419 pendingAcks.clear(); 420 jcb.newGame(); 421 jcb.showMessage("Restarted due to unkown error."); 422 jcb.beep(); 423 acknowledge(line); 424 } else if (message.equals(MOVE_MESSAGE) && value != null) { 425 // Move 426 acknowledge(line); 427 jcb.makePeersMove(new Move(value)); 428 } else if (message.equals(REQUEST_UPLOAD_MESSAGE)) { 429 Object[] options = { "Accept", "Reject" }; 430 int selection = 431 JOptionPane.showOptionDialog( 432 null, 433 "Opponent wants to upload a saved game.", 434 "Accept upload?", 435 JOptionPane.YES_NO_OPTION, 436 JOptionPane.QUESTION_MESSAGE, 437 null, 438 options, 439 options[0]); 440 acknowledge(line); 441 if (selection == JOptionPane.YES_OPTION) { 442 sendMessage(ACCEPT_UPLOAD_MESSAGE); 443 } else { 444 sendString(REJECT_UPLOAD_MESSAGE); 445 } 446 } else if (message.equals(ACCEPT_UPLOAD_MESSAGE)) { 447 acknowledge(line); 448 jcb.showMessage("Upload accepted."); 449 jcb.uploadGame(); 450 } else if (message.equals(REJECT_UPLOAD_MESSAGE)) { 451 acknowledge(line); 452 jcb.showMessage("Upload rejected."); 453 } else if (message.equals(START_UPLOAD_MESSAGE)) { 454 jcb.newGame(); 455 jcb.showMessage("Peer started to upload a game..."); 456 gameIsLoading = true; 457 jcb.beep(); 458 acknowledge(line); 459 } else if (message.equals(BATCH_MOVE_MESSAGE) && value != null) { 460 Move move = new Move(value); 461 jcb.makeBatchMove(move); 462 gameIsLoading = true; 463 acknowledge(line); 464 } else if (message.equals(BATCH_FINISHED_MESSAGE)) { 465 acknowledge(line); 466 jcb.showMessage("Game successfully loaded."); 467 jcb.whitePlayer=JChessBoard.UNKNOWN; 468 jcb.blackPlayer=JChessBoard.UNKNOWN; 469 jcb.gameTable.setNetworkGameIndex(jcb.gameTable.getCurrentGameIndex()); 470 jcb.chessClock.stopClock(); 471 jcb.chessClock.resetClocks(); 472 jcb.update(); 473 jcb.prepareMove(); 474 gameIsLoading = false; 475 } else if (message.equals(BATCH_CANCELED_MESSAGE)) { 476 acknowledge(line); 477 jcb.showMessage("Game upload canceled!"); 478 gameIsLoading = false; 479 } 480 // Initializaton from FEN 481 else if (message.equals(INIT_FROM_FEN_MESSAGE) && value != null) { 482 acknowledge(line); 483 VirtualBoard vb = new VirtualBoard(); 484 vb.initFromFEN(value); 485 jcb.newGame(vb); 486 jcb.showMessage("Opponent initialized board from FEN."); 487 } 488 // Side switch 489 else if (message.equals(REQUEST_SIDE_SWITCH_MESSAGE)) { 490 jcb.beep(); 491 Object[] options = { "Accept", "Reject" }; 492 int selection = 493 JOptionPane.showOptionDialog( 494 null, 495 "Opponents wants to switch sides.", 496 "Switch sides?", 497 JOptionPane.YES_NO_OPTION, 498 JOptionPane.QUESTION_MESSAGE, 499 null, 500 options, 501 options[0]); 502 acknowledge(line); 503 if (selection == JOptionPane.YES_OPTION) { 504 jcb.switchSides(); 505 sendMessage(SIDE_SWITCH_ACCEPTED_MESSAGE); 506 } else { 507 sendMessage(SIDE_SWITCH_REJECTED_MESSAGE); 508 } 509 } else if (message.equals(SIDE_SWITCH_ACCEPTED_MESSAGE)) { 510 acknowledge(line); 511 jcb.switchSides(); 512 } else if (message.equals(SIDE_SWITCH_REJECTED_MESSAGE)) { 513 acknowledge(line); 514 jcb.showMessage("Side switch rejected"); 515 } 516 // Message 517 else if (message.equals(USER_MESSAGE) && value != null) { 518 acknowledge(line); 519 jcb.showMessage(otherPlayersName + ": " + stripCmd(line), "chatIn"); 520 } 521 // Player name 522 else if (message.equals(PLAYER_NAME_MESSAGE) && value != null) { 523 acknowledge(line); 524 otherPlayersName = value; 525 jcb.showMessage("Opponent set its name to \"" + value + "\"."); 526 jcb.updateSTR(); 527 } 528 // Error 529 else if (message.equals(ERROR_MESSAGE)) { 530 acknowledge(line); 531 if (value == null) { 532 jcb.showMessage("An unspecified error occurred."); 533 } else { 534 jcb.showMessage("Error message from peer: " + value); 535 } 536 // history.clear(); 537 // newGame(); 538 } else { 539 // Send outOfSync message 540 sendString("?\n"); 541 } 542 } // Not an acknowledgement 543 } // Not a null message 544 } 545 546 /** 547 * Sends string, setting GUI connection indicator and debug output. 548 */ sendString(String s)549 protected void sendString(String s) { 550 jcb.connectionIndicator.setWaiting(); 551 if (jcb.settings.debugDumpTraffic) { 552 jcb.showMessage(">>>" + s, "debug"); 553 } 554 pendingAcks.add(s); 555 jcb.boardConnector.sendString(s); 556 } 557 558 /** 559 * Sends a message with values. 560 * @param message The message indicator, one of an enumeration of Strings 561 * @param value_line The values required for the message indicator 562 */ sendMessage(String message, String value_line)563 public void sendMessage(String message, String value_line) { 564 if (value_line == null) 565 value_line = ""; 566 sendString(message + " " + value_line); 567 } 568 569 /** 570 * Sends a message with no values. 571 * @param message The message indicator, one of an enumeration of Strings 572 */ sendMessage(String message)573 public void sendMessage(String message) { 574 sendString(message); 575 } 576 577 /** 578 * Sends acknowledgement string. This indicates that we have received 579 * a message send by the connected board. It <em>does not</em> indicate 580 * that the message has been correctly processed. 581 */ acknowledge(String s)582 protected void acknowledge(String s) { 583 if (jcb.settings.debugDumpTraffic) { 584 jcb.showMessage(">>>OK " + s, "debug"); 585 } 586 jcb.boardConnector.sendString("OK " + s); 587 } 588 589 /** 590 Strip off the first "word" which is the command, leaving 591 just the remaining line. 592 */ stripCmd(String line)593 private static String stripCmd(String line) { 594 StringTokenizer st = new StringTokenizer(line); 595 if (st.hasMoreTokens()) { 596 String cmd = st.nextToken(); 597 return (line.substring(cmd.length())); 598 } else { 599 return ("EmptyString"); 600 } 601 } 602 Protocol(JChessBoard _jcb)603 public Protocol(JChessBoard _jcb) { 604 jcb = _jcb; 605 } 606 607 /** 608 * @return 609 */ getOtherPlayersName()610 public String getOtherPlayersName() { 611 return otherPlayersName; 612 } 613 614 /** 615 * @param string 616 */ setOtherPlayersName(String string)617 public void setOtherPlayersName(String string) { 618 otherPlayersName = string; 619 } 620 621 } 622