⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 controller.java

📁 ErGo是一个很早的Java通用围棋服务器(IGS/NNGS)客户端程序。有全部源码和文档
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
    catch (ParseException e) {
      if (previousKibitz == null)
	Debug.backtrace(e);
      else {
	try {
	  String kibitzer = previousKibitz.stringAt(1);
	  String rank = previousKibitz.stringAt(2);
	  String white = previousKibitz.stringAt(3);
	  String black = previousKibitz.stringAt(4);
	  int game = previousKibitz.intAt(5);
	  skipwhite(p);
	  client.displayKibitz(white, black, game, kibitzer, rank, p.rest());
	}
	catch (ParseException foo) {
	  Debug.backtrace(foo);
	}
      }
      previousKibitz = null;	// done with it.
    }
  }

  // SAY = 19
  // Say messages looks like tells:
  //   19 *bug*: hi there
  // Add them as kibitzes to the game being played.
  private void handleSay (ParsedMessage p) {
    client.displaySay(p.rest());
  }

  // INFO = 9
  // Messages that should have been defined in the protocol but aren't
  // are caught here.  Bleuch.
  //
  private void handleInfo (ParsedMessage p) {
    ParsedMessage pmess = null;
    String rest = p.rest();
    client.displayString(rest);

    // Attempt to check for more common messages first, to avoid
    // attempting to parse the message multiple times if not necessary.

    // WING sends "9 \u0007" as beep whereas NNGS sends "2 \u0007"
    if (rest.startsWith("\u0007")) {
      client.beep();
      return;
    }

    // Removing a group during scoring?
    if (previousPrompt == 7) {	// 7 = scoring mode
      try {
	ParsedMessage p1 = new ParsedMessage(rest, " Removing @ %a");
	client.removeGroupAt(p1.stringAt(0));
      }
      catch (ParseException e1) {}
    }

    // Has the komi changed?  Protocol for this is fukt:
    // 9 Komi is now set to 1.5
    // 9 Set the komi to 1.5
    // 9 Komi set to 1.5 in match 3         // new on NNGS
    try {
      ParsedMessage mkomi = null;
      try {
	mkomi = new ParsedMessage(rest, " Set the komi to %f");
      } catch (ParseException e1) {}
      if (mkomi == null)
	try {
	  mkomi = new ParsedMessage(rest, " Komi is now set to %f");
	} catch (ParseException e2) {}
      if (mkomi == null) {
	// New: at my request, NNGS now sends the komi changes to observers.
	mkomi = new ParsedMessage(rest, " Komi set to %f in match %i");
	double komi = mkomi.doubleAt(0);
	int match = mkomi.intAt(1);
	client.setKomi(komi, match);
	return;
      }
      else {
	client.setKomi(mkomi.doubleAt(0), -1);
	return;			// the message has been handled.
      }
    } catch (ParseException e2) {}

    // Match request?
    // 9 Match[19x19] in 1 minute requested with jkong as White.
    // 9 Use <match jkong B 19 1 10> or <decline jkong> to respond.
    // *wms*: CLIENT: <cgoban 1.8.0> match wms wants handicap 5, komi 1.5
    try {
      // The last frob in the "regexp" is an int so it won't include
      // the ">" character.
      ParsedMessage mm
	= new ParsedMessage(rest, " Use <match %s %s %s %s %i");
      client.displayMatchRequest(mm.stringAt(0), // requester
				 mm.stringAt(1), // mycolor
				 mm.stringAt(2), // size
				 mm.stringAt(3), // initial time
				 ((Integer) mm.matchAt(4)).toString()); // byotime
      return;
    }
    catch (ParseException e3) {}
					     
    // 9 2 minutes were added to your opponents clock
    // 9 Your opponent has added 2 minutes to your clock.
    //
    /*
    try {
      ParsedMessage mm = new ParsedMessage(rest, " Your opponent has added %i minutes");
      client.addTime(GoClient.LocalPlayer, mm.intAt(0));
    }
    catch (ParseException e3) {
      try {
	ParsedMessage mm = new ParsedMessage(rest, " %i minutes were added");
	client.addTime(GoClient.RemotePlayer, mm.intAt(0));
      }
      catch (ParseException e213321) {}  // why force me to give it a goddamn name?
    }
    */

    // 9 Removing game 8 from observation list.
    try {
      ParsedMessage rem = new ParsedMessage(rest, " Removing game %i from ob");
      client.unobserveGame(rem.intAt(0));
      return;
    }
    catch (ParseException e4) {}

    String fteachString = "This is now a FREE, UNRATED teaching game.";
    if (rest.regionMatches(true, 0, fteachString, 0, fteachString.length())) {
      client.makeGameFree(-1);  // -1 means active game
    }

    if (lookForPlayerStats) {
      // Look for the player's name and rank.  The rank is needed for
      // for when the player kibitzes, and the name is checked to
      // correct possible character case problems on NNGS.
      try {
	ParsedMessage message = new ParsedMessage(rest, " Player: %s");
	String acct = message.stringAt(0);
	// Maybe correct the character case of the username on NNGS...
	if (client.getAccountName().equalsIgnoreCase(acct))
	  client.setAccountName(acct);
	return;
      }
      catch (ParseException e5) {
	try {
	  ParsedMessage message = new ParsedMessage(rest, " Rating: %s ");
	  client.setAccountRank(message.stringAt(0));
	  lookForPlayerStats = false;
	  return;
	}
	catch (ParseException e6) {
	  try {
	    ParsedMessage message = new ParsedMessage(rest, " Rank: %s ");
	    client.setAccountRank(message.stringAt(0));
	    lookForPlayerStats = false;
	    return;
	  }
	  catch (ParseException e7) {}
	}
      }
    }
    // Ratings updates.
    // 9 Ratings update: You are still 1d* (3003, 18 rated games)
    // 9 Ratings update: You are now 1d* (3003 (were 3002), 18 rated games)
    // We only pay attention to the latter message (i.e., changes in rating)
    try {
      ParsedMessage rat
        = new ParsedMessage(rest, " Ratings update: You are now %s");
      client.setAccountRank(rat.stringAt(0));
      Debug.println("Rank set to " + rat.stringAt(0));
      return;
    }
    catch (ParseException e8) {}

    // UNDO during scoring mode.
    // On NNGS this is handled like a normal UNDO of the last PASS move,
    // and then the PASS move is resent.  The following is for IGS only.
    if (rest.startsWith
	("Board is restored to what it was when you started scoring"))
      client.getGameBeingPlayed().undoDuringServerScoring();

  } // end method handleInfo


  // Deal with * at end of name for "replayed games" on IGS
/*
  private String trimmedName (String name) {
    int len = name.length();
    return ((len > 0 && name.charAt(len - 1) == '*')
	    ? name.substring(0, len - 1) : name);
  }
*/

  /*
   * Handle special tells.
   */
  private void handleTell (ParsedMessage pm) {
    String rest = pm.rest();
    client.displayTell(rest);
    /* removed during switch from TerminalWindow to GoClient.
       was never fully implemented anyway.
    if (currentMatchDialog != null) {
      // Handle tells of the following form:
      // *wms*: CLIENT: <cgoban 1.8.0> match wms wants handicap 5, komi 1.5
      int space = rest.indexOf(' ', 2);
      if (space != -1 && rest.startsWith("CLIENT: ", space + 1)) {
	try {
	  pm.continueParse(" %s CLIENT: <%s %s match %s wants handicap %i, komi %s");
	  currentMatchDialog.setHandicap(pm.intAt(5));
	  currentMatchDialog.setKomi(pm.stringAt(6));
	  currentMatchDialog = null;
	}
	catch (ParseException e1) {
	  Debug.backtrace(e1);
	}
      }
    }
    */
  }

  /*
   * Handle a MOVE message.  The fact that this message is broken
   * into two parts makes it much harder to deal with.  I could
   * handle it by just calling conn.readLine again after the first
   * part is received, but then none of the error checking that
   * happens in the main loop would pertain.  So instead I use a bunch
   * of variable to hold some of the info I need from the first part.
   * It's beyond me why they didn't make this a one line message in
   * the so-called protocol.
   *
   * Format:
   *   15 Game 1 I: whitename (2 591 24) vs blackname (4 222 2)
   *                          ^^^^^^^^^^              ^^^^^^^^^
   *                        (captured timeleft byo-stones)
   *                        byo-stones = -1 means not in byo-yomi
   *      Game 79 I: xiaoren* (0 0 -1) vs NaiWei* (0 72 -1)
   *   15 83(B): A1
   *   15 83(B): handicap 4
   *   15 83(B): pass
   *
   * Note that in the case of the "moves" command the header line
   * is only sent once, at the beginning.  - AMB.
   */

  // Result of most recent "Game ..." move message.
  private ParsedMessage handleMovesMessage;

  // Window of game corresponding to handleMovesMessage (above).
  // useful scope of this is between header and body of handleMove().
  private GameWindow handleMovesWindow;

  // Number of game that handleGames() should look for and add
  // to the observation list.  Normally -1, meaning none.
  // scope of this is *between* handleMoves and the handleGames in question.
  private int handleMovesGame = -1;

  // this little block deals with waiting for the end of the "moves"
  // command before we show the board.

  // all these three are set simultaneously when handleGames receives
  // the game with number equal to handleMovesGame.
  private int waitingMoveNumber = -1;
  private boolean seenmoveone = false;
  private GameWindow waitingGameWindow = null;

  // all three are *only* unset by this function, currently with 3 calls
  // in this class.
  private void visifyPendingGame() {
    if (waitingGameWindow == null) return;
    waitingMoveNumber = -1;
    seenmoveone = false;
    waitingGameWindow.game.ss.setQuiet(false);
  }   

  // Note, importantly, that the reaction of the server on beginning
  // to observe a game after sending the pointless observe message, is
  // to send an empty moves header. This hits the first branch of the
  // if here, which triggers a games command for just that game within
  // handleGames.... this then rekicks back a moves command, and
  // control returns here to deal with the rest of the moves.....
  // What a protocol.....!  AMB, light dawning at 0.6.

  protected void handleMove (ParsedMessage p) throws ErgoException {
    skipwhite(p);
    String input = p.rest();
    if(input.regionMatches(true, 0, "Game", 0, 4)) {
      handleMovesMessage = p;
      try {
	p.continueParse("Game %i %c: %s (%i %i %i) vs %s (%i %i %i)");

	int gameNumber = p.intAt(1);
	String white = p.stringAt(3);
	String black = p.stringAt(7);

	handleMovesWindow = client.getGameWindowByName(white, black,
						       gameNumber);
	if (handleMovesWindow == null) {
	  // There's no game window for this game yet, meaning it was
	  // just added to the observation list.  Save the game number
	  // and issue a "games n" command so that handleMoves will
	  // create a window when it next parses a message for this game.
	  // The reason for this roundabout method is that there isn't
	  // enough info in any one message sent by the server that has
	  // all the info needed to create a game window (specifically,
	  // the game size can only be found in the "games" command's
	  // output).

	  // Bug Fix - if we are already pending the results of the "games"
	  // command, do not send "games" for this or any other game until
	  // they arrive. AMB at 0.8
          if (handleMovesGame == -1) {
	    handleMovesGame = gameNumber;
	    //            System.out.println("Received " + input + ";
	    //            hMG was -1, set to "+handleMovesGame); 
	    conn.send("games " + gameNumber, false);
	  }
	  return; 
	}
	else { // there exists a window for this move.
	  //	  if (gameNumber == handleMovesGame)
	  //    handleMovesGame = -1; // I *believe* this
	  //    line can in fact go completely, since handleGames()
	  //    will set hmG to -1 itself when it has successfully 
	  //    made the window. AMB of 0.8.
	  // if we receive *any* move header after move one seen of pending game,
	  // must show window.
          if (waitingMoveNumber > -1 && seenmoveone) {
            visifyPendingGame();
	  }
	  handleMovesWindow.
	    updateTimers(p.intAt(4), // wcapt
			 p.intAt(5), // wtime
			 p.intAt(6), // wstones
			 p.intAt(8), // bcapt
			 p.intAt(9), // btime
			 p.intAt(10)); // bstones
	}
      }
      catch (ErgoException woof) {
	Debug.backtrace(woof);
	handleMovesMessage = null;
      }
    }
    else { // this is the second branch of the Moves message....
      if (handleMovesMessage == null || handleMovesWindow == null) {
	return; }
      // Format of input is  "15 83(B): A1", "15 83(B): handicap 4",
      // or "15 83(B): Pass"
      try {
	p.continueParse("%i(%c): %a");

	int moveNumber = p.intAt(1);
	char player = ((Character) p.matchAt(2)).charValue();
	int color = (player == 'B') ? Move.BLACK : Move.WHITE;
	int field = (player == 'B') ? 5 : 9;
	int timeleft = handleMovesMessage.intAt(field);
	Move parent = handleMovesWindow.game.finalServerMove();

	if (moveNumber != parent.moveNumber() + 1) {
	  //Debug.println("handlemove(): Move received out of order.  Parent = "
	  //	     + parentNum + ". New = " + moveNumber 
	  //         + ".  Move message = " + p.message());
	  // This is almost certainly due to an UNDO (which resends the
	  // previous move) or an auto-re-observer of the game.  Just
	  // ensure that the game knows it's now active, not adjourned.
	  // +++ Should really pass the correct times to ensureActive.
	  //
	  // NB - The other important case is where current moves from the game
	  // just becoming observed arrive before the output of the "moves"
	  // command from handleGames. This code solves that bug, and also
	  // the "slow history drawing" bug..... AMB at 0.7
	  handleMovesWindow.ensureActive();
	  return;
	}
	// Are we waiting for a moves command to finish for this game?
        if (waitingMoveNumber > -1 && handleMovesWindow == waitingGameWindow) {
          if (moveNumber == 1) {
            seenmoveone = true;
	  }
          if (moveNumber >= waitingMoveNumber - 1) {
	    // Have finished the accelerated portion of an observed game. AMB
	    // Show the position now...
            visifyPendingGame();
	  }
	}
	Move move;
	String string = p.stringAt(3);
	if (string.regionMatches(true, 0, "ha", 0, 2)) { // handicap move?
	  p.continueParse(" %i");
	  int stones = p.intAt(4);
	  move = new HandicapMove(parent, timeleft, moveNumber, false,
				  stones, handleMovesWindow.game.size()); }
	else if (string.regionMatches(true, 0, "pa", 0, 2)) {  // pass move?
	  move = new PassMove(parent, timeleft, moveNumber, color, false);
	}
	else {
	  Position pos = new Position(string, handleMovesWindow.game.size());
	  move = new StoneMove(parent, timeleft, moveNumber, color,
			       false, pos);
	}
	handleMovesWindow.placeMove(move, true);
        handleMovesWindow.game.ss.emit();
      }
      catch (ParseException e) {
	Debug.backtrace(e);
      }
    }
  }	// end method handleMove



  /*
   * GAMES
   *
   * Message format:
   * [##]  white name [ rk ]      black name [ rk ] (Move size H Komi BY FR) (###)
   * [30]      BUDDYM [ 1k*] vs.        guen [ 2k*] (  0   19  0  0.5  8  I) (  0)
   *

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -