/**
   * 指定したサイズ、置石で棋譜の{@link RootGameTree}を作成します。
   *
   * @param sgfSize 碁盤の大きさ
   * @param handicap 置石の数(0:互先, 1:定先、2:二子…)
   * @return 作成した棋譜。NOT NULL
   * @throws org.unitarou.lang.NullArgumentException 引数が <code>null</code>の場合
   * @throws IllegalArgumentException sgfSizeが正方形以外でnumberが2以上の場合
   */
  public static RootGameTree createGame(SgfSize sgfSize, Handicap handicap) {
    ArgumentChecker.throwIfNull(sgfSize, handicap);

    RootGameTree rgt = new RootGameTree();
    rgt.setSize(sgfSize);
    rgt.setFileFormat(FileFormat.VERSION_4);
    rgt.setCharset(new SgfCharset(Charset.defaultCharset()));
    rgt.setGameMode(GameMode.IGO);
    rgt.setGameType(GameType.GAME);
    rgt.setStyle(Style.SIBLINGS_SHOW_VAL);

    Node node = rgt.getSequence().getFirst();
    node.addProperty(SgfId.HANDICAP.makeProperty(handicap));
    node.addProperty(
        SgfId.PLAYER_TO_PLAY.makeProperty(
            (1 < handicap.getIntValue()) ? SgfColor.WHITE : SgfColor.BLACK));

    Set<SgfPoint> handicappedStones = composeHandicapStone(sgfSize, handicap);
    if (!handicappedStones.isEmpty()) {
      node.addProperty(SgfId.ADD_BLACK.makeProperty(handicappedStones));
    }
    return rgt;
  }
  /**
   * 引数の条件に合致した置き石を返します。
   *
   * @param sgfSize
   * @param handicap
   * @throws IllegalArgumentException sgfSizeが正方形以外でnumberが2以上の場合
   * @return 置き石の座標。NOT NULL
   */
  private static Set<SgfPoint> composeHandicapStone(SgfSize sgfSize, Handicap handicap) {
    int hd = handicap.getIntValue();
    if (hd < 2) {
      return Collections.emptySet();
    }

    if (sgfSize.width() != sgfSize.height()) {
      throw new IllegalArgumentException();
    }

    Set<SgfPoint> pointSet = new HashSet<SgfPoint>(9);

    final int size = sgfSize.width();
    int left = size + 1, middle = size + 1, right = size + 1;

    if (size < 9) {
      left = size / 5 + 1;
      right = size - left + 1;
      middle = size / 2 + 1;

    } else if (size < 13) {
      left = 3;
      right = size - left + 1;
      middle = size / 2 + 1;
    } else {
      left = 4;
      right = size - left + 1;
      middle = size / 2 + 1;
    }

    switch (hd) {
      case 9:
        pointSet.add(SgfPoint.create(sgfSize, middle, left));
        pointSet.add(SgfPoint.create(sgfSize, middle, right));

      case 7:
        pointSet.add(SgfPoint.create(sgfSize, right, middle));
        pointSet.add(SgfPoint.create(sgfSize, left, middle));

      case 5:
        pointSet.add(SgfPoint.create(sgfSize, middle, middle));

      case 4:
        pointSet.add(SgfPoint.create(sgfSize, right, right));

      case 3:
        pointSet.add(SgfPoint.create(sgfSize, left, left));

      case 2:
        pointSet.add(SgfPoint.create(sgfSize, right, left));
        pointSet.add(SgfPoint.create(sgfSize, left, right));
        break;

      case 8:
        pointSet.add(SgfPoint.create(sgfSize, middle, left));
        pointSet.add(SgfPoint.create(sgfSize, middle, right));

      case 6:
        pointSet.add(SgfPoint.create(sgfSize, right, middle));
        pointSet.add(SgfPoint.create(sgfSize, left, middle));
        pointSet.add(SgfPoint.create(sgfSize, right, right));
        pointSet.add(SgfPoint.create(sgfSize, left, left));
        pointSet.add(SgfPoint.create(sgfSize, right, left));
        pointSet.add(SgfPoint.create(sgfSize, left, right));
    }

    return pointSet;
  }