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

📄 controller.java

📁 ErGo是一个很早的Java通用围棋服务器(IGS/NNGS)客户端程序。有全部源码和文档
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
   * When the output of the games command is received we check to see if
   * the user is observing that game, and if so update the title of that game.
   *
   * this constructs Game Windows by use of handleMovesGame....
   * it issues the "moves" command to acquire the game history. AMB
   */
  protected void handleGames(ParsedMessage p) {
    skipwhite(p);
    String mess = p.rest();
    if (mess.indexOf("white name") != -1 && handleMovesGame == -1) {
      sgc.clear();
    }
    try {
      p.continueParse("[ %i ] %s [ %w ] vs. %s [ %w ] ( %i %i %i %f %i %w ) ( %i )");
      // fields ->       1    2    3        4    5      6  7  8  9  10  11    12
      int n = p.intAt(1);	// game number
      String w = p.stringAt(2);
      String b = p.stringAt(4);
      String flags = p.stringAt(11); // e.g., "FI" = Free, IGS rules.
      String acctName = client.getAccountName();
      boolean teachingGame = flags.indexOf("T") != -1;
      boolean freeGame = flags.indexOf("F") != -1;
      boolean playing = w.equals(acctName) || b.equals(acctName);
      int matchi = -1;
      if ((w.equals(b) && w.equals(acctName))
	  || (playing && teachingGame))
	matchi = Move.BOTH;
      else if (w.equals(acctName))
	matchi = Move.WHITE;
      else if (b.equals(acctName))
	matchi = Move.BLACK;
      // getGameWindowByName will invalidate any other window with
      // game# = n, and will update its title if necessary.
      GameWindow gwin = client.getGameWindowByName(w, b, n);

      String wr = p.stringAt(3);
      String br = p.stringAt(5);
      int size = p.intAt(7);
      int handi = p.intAt(8);
      double komi = p.doubleAt(9);
      int byotime = p.intAt(10);
      sgc.apply(p.stringAt(1), w, wr, b, br, p.stringAt(6),
		p.stringAt(7), p.stringAt(8), p.stringAt(9),
		p.stringAt(10), flags, p.stringAt(12), true);
      // problem here, no announcement of end of games.......!
      if (handleMovesGame != -1) { // this means that this issue of
				   // the games command is by handleMoves().
        countergames = true; // do not show the window after this.
	// handleMoves has just seen the first move for a new game.
	// The window is created here because the "games" command is
	// the only (?) place to find out the size of the game.  The
	// other needed info has already been saved in handleMovesMessage.
	// Issue a "moves" message for this game so the board will
	// get refreshed.
	gwin = client.addGameWindow(size, w, wr, b, br, komi, n, matchi, byotime, freeGame);
	conn.send("moves " + n, false);
        int waitingMove = p.intAt(6);
        if (waitingMove > 0) {
          waitingGameWindow = gwin;
          waitingMoveNumber = waitingMove;
          gwin.game.ss.setQuiet(true);
          seenmoveone = false;
        }
	handleMovesGame = -1;
      }
    }
    catch (ErgoException e) {}
  } // end method handleGames


  /*
   * Handle a prompt.  For reference, here is the list of prompt types from
   * the protocol document.
   *
   * LOGON	= 0,   initial state 
   * PASSWORD	= 1,   getting password 
   * PASSWD_NEW	= 2,   verifiying password: not used, registration 
   * PASSWD_CONFIRM	= 3,   ditto 
   * REGISTER	= 4,   not used 
   * WAITING	= 5,   After login the basic state 
   * PLAYING	= 6,   Playing a game 
   * SCORING	= 7,   Scoring a game 
   * OBSERVING	= 8,   Observing (and playing?) a game 
   * TEACHING	= 9,   In teaching mode, can move for W and B 
   * COMPLETE	= 10   game complete 
   */

  private int previousPrompt = 0;

  protected void handlePrompt(ParsedMessage p) {
    try {
      p.continueParse(" %i");
      int n = p.intAt(1);
      switch (n) {
      case 1:
	// Getting password (only if client was toggled on initially)
	client.displayString("Password: ", null, true);
	if (client.loginDialogExists()
	    && client.loginDialogDone()
	    && !client.passwordSent()) {
	  client.sendPassword();
	}
	break;
      case 7:
	if (n != previousPrompt && conn.server.isNNGStype()) {
	  // We just entered scoring mode.  On NNGS (as of 1998-01-17) there
	  // is a bug on NNGS such that the second Pass move in a row is not
	  // sent to both players in the game.  Instead the game goes directly
	  // into scoring mode by sending prompt 7.  This is not the case on
	  // IGS.  Since I use 2 Pass moves to know when to enter scoring
	  // mode (so that it will work the same in server games as it does
	  // in local games), this poses a problem.  Until the bug is fixed
	  // on NNGS (I reported it today) I will generate a Pass move here.
	  GameWindow gwin = client.getGameBeingPlayed();
	  Move parent = gwin.game.finalServerMove();
	  int movenum = parent.moveNumber() + 1;
	  int color = Move.nextColor(parent.color());
	  PassMove m = new PassMove(parent, 0, movenum, color, false);
	  // Why does this use handleMovesWindow rather than gwin?
	  handleMovesWindow.placeMove(m, true);
	}
	client.displayStringInActiveGame("Enter dead group:");
	break;
      default:
	conn.stopScanningForLogin();
	break;
      }
      previousPrompt = n;
    }
    catch (ErgoException e) { }
  }

  /*
   * Undo has two formats:
   *   While playing:    28 sigue undid the last move (C7).
   *   While observing:  28 Undo in game 6: vhdl vs snapback:  C9
   * It is then followed immediately by the previous move:
   *   15 Game 12 I: sigue (0 600 -1) vs sigue (0 600 -1)
   *   15   0(B): G3
   */
  protected void handleUndo(ParsedMessage p) {
    // Need to find out what game the undo is for...
    GameWindow gwin;
    try {
      // Is it the format of a game that's being observed?
      p.continueParse(" Undo in game %i: %a vs %a: %a");
      int gameNumber = p.intAt(1);
      String white = p.stringAt(2);
      String black = p.stringAt(3);
      client.undoMove(white, black, gameNumber);
    }
    catch (ParseException e) {
      // Not a game being observed, so must be playing a game.
      client.undoMove();
    }
  }


  /** 
    * Deal with "shouts", which are not just shouts.
    *
    * Examples:
    * {Game 16: smount vs cht : W 67.5 B 120.0}
    * {Game 15: fanzhen vs indigo : White resigns.}
    * {Game 15: fanzhen vs indigo : White forfeits on time.} // NNGS & IGS
    * {Game 15: fanzhen vs indigo : White lost by Time.}     // IGS
    * {Game 18: seanlarsen vs gremlin has adjourned.}
    * {Game 47: Allegro vs a11 @ Move 71}
    * {Match 15: kado [ 5k*] vs. anhui [ 6k*] }
    * {sisi [ 6k*] has connected.}
    * {cinnabar has disconnected.}
    * !JeryGarcia!: anyone 9x9, or 13x13 with 30k?
    */
  protected void handleShout (ParsedMessage p) {
    skipwhite(p);
    String message = p.rest();
    switch (message.charAt(0)) {
    case '{':
      try {
	// First case: end, resumption or adjournment of a game.
	if (message.regionMatches(true, 0, "{Game ", 0, 6)) {
	  p.continueParse("{Game %i: %a vs %a "); // What happend to "Match"? AMB
	  int gnum = p.intAt(1);
	  String white = p.stringAt(2);
	  String black = p.stringAt(3);
	  String rest = p.rest();
	  if (rest.indexOf("adjourned.}") != -1) { // case 1: adjourn
	    client.adjournGame(white, black, gnum);
	    sgc.disapply(gnum, white, black);
	    break;		// exit the switch
	  }
	  // Try to find out the SGF result of the game.
	  // Hold your nose...
	  String score = "";
	  String winner = "";
	  if (rest.indexOf(" B ") != -1) { // case 2: result
            if (client.isDisplayingGame(white, black, gnum)) {
	      try {
		// WING Note: A finished, scored game looks like this:
		// {Game 1: foo vs bar : W 82.5 B 76.0 White wins by 6.5.}
		// So this won't display the result correctly on WING.

		// The first two %s's are to strip off "White resigns."
		ParsedMessage ugh
		  = new ParsedMessage(rest, " : %s %s %s %f %s %f");
		double whiteScore = ugh.doubleAt(3);
		/* 
		  ParseException: Illegal field access - asked for 5.
		  at ParsedMessage.matchAt(util.java:598)
		  at Controller.handleShout(Controller.java:1028)
		  at Controller.dispatchMessage(Controller.java:275)
		  at Controller.run(Controller.java:157)
		  at java.lang.Thread.run(Thread.java:474)

		  The following call to matchAt blew out with the above.
		  The score was successfully displayed, but there was
		  no SGF result displayed.  I think the IGS messages
		  may have changed.
		  */
		double blackScore = ugh.doubleAt(5);
		score = "" + Math.abs(whiteScore - blackScore);
		winner = (whiteScore < blackScore) ? "B" : "W";
		client.resignGame(white, black, gnum, winner + "+" + score);
	      }
	      catch (ParseException grunt) {
		Debug.backtrace(grunt);
	      }
	    }
	    sgc.disapply(gnum, white, black);
	    break;		// exit the switch
          }
	  else if (rest.indexOf("resigns.}") != -1) { // case 3: resign
	    score = "Resign";
	    winner = (rest.indexOf("White") != -1) ? "B" : "W";
	    client.resignGame(white, black, gnum, winner + "+" + score);
	    sgc.disapply(gnum, white, black);
	    break;		// exit the switch
	  }
//     {Game 15: fanzhen vs indigo : White forfeits on time.} // NNGS & IGS
//     {Game 15: fanzhen vs indigo : White lost by Time.}     // IGS
// The latter is (I believe) only used on IGS for games that were
// replayed at the request of a user.  Need to verify this.
	  else if (rest.indexOf("forfeit") != -1 // case 4: time
		   || rest.indexOf("Time") != -1) { // IGS requested games.
	    score = "Time";
	    winner = (rest.indexOf("White") != -1) ? "B" : "W";
	    client.resignGame(white, black, gnum, winner + "+" + score);
	    sgc.disapply(gnum, white, black);
	    break;		// exit the switch
	  }
	  else if (rest.indexOf("@ Move") != -1) { // case 5: resume
            if (client.isDisplayingGame(white, black, gnum))
	      conn.send("observe " + gnum); // auto re-observe game.
	    p.continueParse("@ Move %i");
	    ServerPlayer spw = spc.byName(white);
	    ServerPlayer spb = spc.byName(black);
	    String wrank = (spw == null ? "??" : spw.rank.render());
	    String brank = (spb == null ? "??" : spb.rank.render());
	    sgc.apply(p.stringAt(1), white, wrank, black, brank, p.stringAt(4));
	  }			// end if resume
	}			// end if it is a message beginning "{Game"
	if (message.regionMatches(true, 0, "{Match ", 0, 7)) {
	  p.continueParse("{Match %i: %s [ %w ] vs. %s [ %w ]");
	  // Issue a "games n" command, to automatically update
	  // the "games" window when a new match starts.
	  // +++ The "games" window has to be modified for this to work.
	  //     Currently it erases everything except game n if I
	  //     issue a "games n" command.
	  //conn.send("games " + p.intAt(1));
	  sgc.apply(p.stringAt(1), p.stringAt(2), p.stringAt(3),
		    p.stringAt(4), p.stringAt(5));
	  // New games are important enough to display as terminal output.
	  client.displayString(message);
	}
	else if (message.indexOf(" has connected.}") != -1) {
	  p.continueParse("{%s [ %w ]");
	  spc.apply(p.stringAt(1), p.stringAt(2));
	}
	else if (message.indexOf(" has disconnected}") != -1) {
	  p.continueParse("{%s");
	  ServerPlayer sp = spc.byName(p.stringAt(1));
	  //          System.out.println(sp.name+" is gone");
	  spc.removePlayer(sp, false);
	}
      }				// end try block
      catch (ParseException e) {
        e.printStackTrace(System.out);
      }
      finally {
	// Always display this junk in the noise string area.
	client.displayNoiseString(message);
      }
      break;
    default:
      // If we get to here, I believe message is "!foo! blah blah blah"
      client.displayShout(message);
      break;
    }				// end switch on first character of message...
  }


  protected int[][] gameResult = null;
  protected String gameResultWhite = null;
  protected String gameResultBlack = null;
  private String gameResultWR = null;
  private String gameResultBR = null;
  private double gameResultKomi = 5.5f;

  /* Score looks like this: AMB
     22 Bosmon 25k  0 1570 23 F 5.5 0
     22 paulcc 25k  0 1781 24 F 5.5 0
     22  0: 222222222
     22  1: 222222222
     22  2: 226262022
     22  3: 220222222
     22  4: 226262622
     22  5: 222222222
     22  6: 226262122
     22  7: 222222222
     22  8: 222222222

     The first two lines are
     22 whitename rank n timeleft n T/F komi n

20 ogre (W:O): 57.5 to ogre (B:#): 8.0

20 ogre (W:O): 57.5 to ogre (B:#): 8.0
     */
  protected void handleScore (ParsedMessage pm) {
    String message = pm.rest();
    try {
      pm.continueParse(" %i: %a");
      int column = pm.intAt(1);
      String data = pm.stringAt(2);
      int size = data.length();	// assume square board
      if (gameResult == null) {
	gameResult = new int[size][size];
	for (int i = 0; i < size; i++)
	  for (int j = 0; j < size; j++)
	    gameResult[i][j] = -1;
      }
      for (int i = 0; i < size; i++) {
	char c = data.charAt(i);
	if (Character.isDigit(c))
	  gameResult[size - i - 1][column] = Character.digit(c, 10);
	else
	  break;
      }
      boolean done = (gameResultBlack != null && gameResultWhite != null);
    outer:
      for (int i = 0; i < size; i++)
	for (int j = 0; j < size; j++)
	  if (gameResult[i][j] == -1) {
	    done = false;
	    break outer;
	  }
      if (done) {
	GameWindow gwin = client.getGameWindowByName(gameResultWhite, gameResultBlack, -1);
	if (gwin == null) {
	  // If no game by this name, then this must be the "look" command.
	  // Create a local game with one move, the result.
	  gwin = client.createGame(size, gameResultWhite, gameResultWR,
				   gameResultBlack, gameResultBR, gameResultKomi);
	}
	// Place the move.  The second argument (fromServer) is false
	// because the server doesn't model the game result as a move
	// so it would cause problems if we modelled it as a server move.
	// (e.g., we might try to UNDO it on the server).  I don't think
	// it should cause a problem to treat it as a local move since at
	// the point this move is received the game is over.
	client.placeMove(gameResultWhite, gameResultBlack, -1,
			 new GameResultMove(gwin.game.finalServerMove(), gameResult),
			 false);	// this is a lie, technically.
	gameResult = null;
	gameResultBlack = null;
	gameResultWhite = null;
	gameResultWR = null;
	gameResultBR = null;
      }
    }
    catch (ParseException e) {
      try {
	// 22 Bosmon 25k  0 1570 23 F 5.5 0
	ParsedMessage pmess = new ParsedMessage(message, " %a %s %i %i %i %c %f %i");
	if (gameResultWhite == null) {
	  gameResultWhite = pmess.stringAt(0);
	  gameResultWR = pmess.stringAt(1);
	  gameResultKomi = pmess.doubleAt(6);
	}
	else if (gameResultBlack == null) {
	  gameResultBlack = pmess.stringAt(0);
	  gameResultBR = pmess.stringAt(1);
	}
      }
      catch (ParseException e1) { }
    }
  }


  // Display a yell as "<##:username> text ..."
  // Yell message format is "32 ##:username: text"
  protected void handleYell(ParsedMessage pm) {
    try {
      pm.continueParse(" %s ");
      String from = pm.stringAt(1);
      String text = pm.rest();
      from = from.substring(0, from.length() - 1);
      // +++ from includes the channel number.  should separate them.
      client.displayYell(from, text);
    }
    catch (ParseException pe) {
      client.displayString(pm.rest());
    }
  }

}				// end class Controller

⌨️ 快捷键说明

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