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

📄 sgf.java

📁 ErGo是一个很早的Java通用围棋服务器(IGS/NNGS)客户端程序。有全部源码和文档
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
      // in which case add it to the game.
      // +++ Why bother?  Might as well add them all to the move, some
      //     will just get stored in the root move.
      String[] info = getPropInfo(property);
      if (info == null)
	warn(property + " is not a recognized SGF4 property name.");
      if (info != null && "r".equals(info[PTYPEINDEX]))
	game.addSGFproperty(property, values);
      else
	game.getCurrentMove().addSGFproperty(property, values);
    }
  }

  public static String[] getPropInfo (String prop) {
    for (int i = 0; i < PROPERTIES.length; i++)
      if (PROPERTIES[i][SNAMEINDEX].equals(prop))
	return PROPERTIES[i];
    //Debug.println("Unknown property seen: " + prop);
    return null;
  }

  // Return true if the given property has propvalue type SimpleText.
  boolean isSimpleText (String prop) {
    String[] info = getPropInfo(prop);
    return (info == null) ? false : "s".equals(info[VTYPEINDEX]);
  }

  // Return true if the given property has propvalue type Text.
  // Unrecognized properties are assumed to be of type Text.
  private boolean isText (String prop) {
    String[] info = getPropInfo(prop);
    return (info == null) ? true : "t".equals(info[VTYPEINDEX]);
  }
  
  // Write a string to the output stream, escaping ], \, and :
  public static void writeText (PrintWriter out, String text) {
    StringBuffer buff = new StringBuffer();
    for (int i = 0; i < text.length(); i++) {
      char c = text.charAt(i);
      if (c == ']' || c == '\\' || c == ':')
	buff.append('\\');
      buff.append(c);
    }
    out.print(buff.toString());
  }

  class Node {
    private Vector nodeProperties = new Vector();
    private Vector nodeValues = new Vector();
    
    // When this is called nextChar(in) = ';'
    Node (Reader in, Game game) throws SGFParseException, IOException {
      //Debug.println("parsing a node");
      char c = skipWhite(in);
      if (c != ';')
	error("';' expected at beginning of node.  '" + c + "' found.");
      while (true) {
	c = skipWhite(in);
	if (c == ';' || c == '(' || c == ')') { // Node "follow set"
	  backup();
	  break;
	}
	else if (isAlpha(c)) {
	  // Reading a PropIdent string, such as FF, SZ, GaMe, etc.
	  // c contains the first alphabetic char of the propIdent string.
	  StringBuffer buff = new StringBuffer();
	  buff.append(c);
	  while (true) {
	    c = skipWhite(in);
	    if (isAlpha(c)) {
	      if (isUCAlpha(c))	// ignore lowercase chars in propidents
		buff.append(c);
	    }
	    else if (c == '[') {
	      backup();
	      break;
	    }
	    else
	      error("Alphabetic character or '[' expected, '"
		    + c + "' found.");
	  }
	  String property = buff.toString();
	  //Debug.println("property = " + property);
	  nodeProperties.addElement(property);

	  // Reading a PropValue list such as "[foo]" or "[he][ll]"
	  Vector pvals = new Vector(1, 10); // common case is 1 propval
	  while (skipWhite(in) == '[') {
	    buff.setLength(0);
	    if (isSimpleText(property))
	      readSimpleTextProperty(in, buff);
	    else if (isText(property))
	      readTextProperty(in, buff);
	    else	// No escaping...just copy until ']' reached.
	      while ((c = skipWhite(in)) != ']')
		buff.append(c);
	    pvals.addElement(buff.toString());
	  }
	  backup();
	  //Debug.println("propvalue = " + value);
	  nodeValues.addElement(pvals);
	  notePropertySeen(property, pvals, game);
	}
	else
	  error("Expected ;, (, ), or an alphabetic character at end of node.  '"
		+ c + "' found.");
      } // end while (true)
    } // end Node constructor

    void readTextProperty (Reader in, StringBuffer buff) throws IOException {
      boolean escaped = false;
      char prev = prevChar;
      while (true) {
	char c = nextChar(in);
	if (escaped) {
	  if (!isLineBreakChar(c)) // escaped line breaks removed
	    buff.append(c);
	  escaped = false;
	}
	else {
	  if (c == '\\')	// if we get here, escaped == false
	    escaped = true;
	  else if (Character.isWhitespace(c)) {
	    if (isLineBreakChar(c)) { // deal with CRLF, LFCR, etc.
	      if ((c == prev) || !isLineBreakChar(prev)) {
		buff.append('\n');
	      }
	    }
	    else {
	      c = ' ';
	      buff.append(c);
	    }
	  }
	  else if (c == ']')
	    break;
	  else
	    buff.append(c);
	}
	prev = c;
      }
    }

    void readSimpleTextProperty (Reader in, StringBuffer buff) throws IOException {
      boolean escaped = false;
      while (true) {
	char c = nextChar(in);
	if (escaped)
	  escaped = false;
	else {
	  if (c == '\\') {
	    escaped = true;
	    continue;
	  }
	  else if (Character.isWhitespace(c))
	    c = ' ';
	  else if (c == ']')
	    break;
	}
	buff.append(c);
      }
    }

    // Returns a vector of string property values.  Normally there will
    // only be one element in the vector, but this way it can handle
    // list property values (most notably "list of point").
    private Vector getPropertyValues (String prop) {
      for (int i = 0; i < nodeProperties.size(); i++)
	if (prop.equals((String) nodeProperties.elementAt(i)))
	  return (Vector) nodeValues.elementAt(i);
      return null;
    }

    // This is used for properties that are known not to allow list values.
    private String getPropertyValue (String prop) {
      if (prop == null)
	return null;
      Vector values = getPropertyValues(prop);
      if (values != null && values.size() > 0)
	return (String) values.elementAt(0);
      else
	return null;
    }

    private String getColor () {
      // Black stone move or HAndicap move.
      if (getPropertyValue("B") != null
	  || (getPropertyValue("HA") != null))
	return "B";
      else if (getPropertyValue("W") != null)
	return "W";
      else
	return null;
    }

    // Returns true if this node can be converted into an Ergo Move.
    // This effectively means that it should only return true for
    // nodes which contain a B or W property.  The root move is treated
    // specially here and in toMove() so that kibitzes and such can
    // be added to it.
    private boolean isMove (Game game) {
      return (game.getCurrentMove() instanceof RootMove
	      || getColor() != null);
    }

    // Returns null to signify an invalid position.
    private Position SGFtoPosition (String sgf, int gameSize) throws SGFParseException {
      if (sgf == null || sgf.length() < 2)
	error("Invalid move: " + sgf);
      char rowc = sgf.charAt(1);
      char colc = sgf.charAt(0);
      int col;
      int row;
      if (colc >= 'a' && colc <= 'z')
	col = (int) colc - (int) 'a';
      else
	col = (int) colc - (int) 'A' + 26;
      if (rowc >= 'a' && rowc <= 'z')
	row = (int) rowc - (int) 'a';
      else
	row = (int) rowc - (int) 'A' + 26;
      row = (gameSize - 1) - row; // invert y axis
      if (col < 0 || row < 0)
	error("Invalid move: " + sgf);
      else if (sgf.length() > 2)
	warn("Ignoring extra characters in move: " + sgf);
      return new Position(row, col);
    }

    Move toMove (Game game) throws SGFParseException {
      Move parent = game.getCurrentMove();
      int gameSize = game.size();
      int moveNum = parent.moveNumber() + 1;
      String colorv = getColor();
      int color = ("B".equals(colorv) ? Move.BLACK : Move.WHITE);
      String timelefts = colorv + "L";
      String timeleftv = getPropertyValue(timelefts); // BL or WL
      int timeleft = 0;
      String sgfpos = getPropertyValue(colorv);
      String handicapv = getPropertyValue("HA");
      Move m = null;
      if (timeleftv != null) {
	try {
	  timeleft = Integer.parseInt(timeleftv);
	}
	catch (NumberFormatException e1) {
	  // +++ This warning may have wrong filepos
	  warn("Time left (" + timelefts
		  + ") property invalid, using 0 instead.");
	}
      }
      //Debug.println("toMove: parent = " + parent + ", new moveNum = " + moveNum);
      if ("".equals(sgfpos) || (gameSize <= SGF3_MAXGAMESIZE
				&& "tt".equals(sgfpos))) {
	//Debug.println("making pass move");
	m = new PassMove(parent, timeleft, moveNum, color, true);
      }
      else if (sgfpos != null) {
	//Debug.println("making stone move");
	// +++ Should probably warn here if haven't seen SZ prop yet.
	Position pos = SGFtoPosition(sgfpos, gameSize);
	m = new StoneMove(parent, timeleft, moveNum, color, true, pos);
      }
      else if (handicapv != null) {
	Vector pvals = getPropertyValues("AB");
	if (pvals != null) {
	  // Use the AddBlack property in this node to place the handicap.
	  PositionVector positions = new PositionVector(9);
	  for (int i = 0; i < pvals.size(); i++) {
	    String spos = (String) pvals.elementAt(i);
	    // +++ Should probably warn here if haven't seen SZ prop yet.
	    positions.addElement(SGFtoPosition(spos, game.size()));
	  }
	  m = new HandicapMove(parent, timeleft, moveNum, true, positions);
	}
	else {
	  // There's no AddBlack prop, so place the standard handicap.
	  try {
	    int numStones = Integer.parseInt(handicapv);
	    if (pedantic && numStones < 2)
	      warn("Invalid HAndicap property.  Value must be >= 2.");
	    if (numStones < 0 || numStones > 9) // Ergo can deal with 1
	      error("Invalid HAndicap property.  "
		    + "Value must be between 1 and 9 inclusive.");
	    // Many apps seem to write HA[0] even though that's illegal,
	    // so deal with it here.
	    if (numStones != 0)
	      m = new HandicapMove(parent, timeleft, moveNum, true,
				   numStones, gameSize);
	  }
	  catch (NumberFormatException queRollo) {
	    error("Invalid HAndicap property.  "
		  + "Value must be an integer.");
	  }
	}
      }
      // This doesn't seem to be any other kind of move, so add the
      // properties to the root move.
      else if (game.getCurrentMove() instanceof RootMove)
	m = game.getCurrentMove();
      if (m != null) {
	// Add other properties to the move here.
	for (int i = 0; i < nodeProperties.size(); i++) {
	  String prop = (String) nodeProperties.elementAt(i);
	  // Don't add the properties that are part of the move's type
	  if (prop != null
	      && !("HA".equals(prop) || prop.equals(colorv)
		   || prop.equals(timelefts) || "AB".equals(prop))) {
	    Vector pvals = getPropertyValues(prop);
	    if (pvals != null) {
	      if ("C".equals(prop)) // Kibitzes handled specially.
		for (int k = 0; k < pvals.size(); k++)
		  m.addKibitz((String) pvals.elementAt(k));
	      else
		m.addSGFproperty(prop, pvals);
	    }
	  }
	}
      }
      return m;
    }
      
    public String toString () {
      StringBuffer b = new StringBuffer();
      b.append("Node[");
      for (int i = 0; i < nodeProperties.size(); i++) {
	b.append(nodeProperties.elementAt(i));
	b.append("=");
	b.append(nodeValues.elementAt(i));
	if (i < nodeProperties.size() - 1)
	  b.append(",");
      }
      b.append(']');
      return b.toString();
    }
  } // end inner class Node

} // end class SGF

⌨️ 快捷键说明

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