protected double getUnfinishedCloisterPoints(Cloister cloister, LegacyAiScoreContext ctx) {
   List<Meeple> followers = cloister.getMeeples();
   if (!followers.isEmpty() && isMe(followers.get(0).getPlayer())) {
     openCount[OPEN_COUNT_CLOITSTER]++;
   }
   double chanceToClose = ctx.getChanceToClose();
   int points = ctx.getPoints();
   return points + (9 - points) * chanceToClose;
 }
  protected double getUnfinishedCityPoints(City city, LegacyAiScoreContext ctx) {
    double chanceToClose = ctx.getChanceToClose();

    if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) {
      openCount[OPEN_COUNT_CITY]++;
    }

    // legacy heuristic
    CityScoreContext cityCtx = (CityScoreContext) ctx.getCompletableScoreContext();
    if (chanceToClose < MIN_CHANCE) {
      return cityCtx.getPoints(false) + 3.0 * chanceToClose;
    } else {
      return cityCtx.getPoints(true) - 3.0 * (1.0 - chanceToClose);
    }
  }
  protected double getUnfinishedRoadPoints(Road road, LegacyAiScoreContext ctx) {
    double chanceToClose = ctx.getChanceToClose();
    ;

    if (chanceToClose > MIN_CHANCE && ctx.getMajorOwners().contains(getPlayer())) {
      openCount[OPEN_COUNT_ROAD]++;
    }

    // legacy heuristic
    RoadScoreContext roadCtx = (RoadScoreContext) ctx.getCompletableScoreContext();
    if (chanceToClose < MIN_CHANCE) {
      return roadCtx.getPoints(false) + 3.0 * chanceToClose;
    } else {
      return roadCtx.getPoints(true) - 3.0 * (1.0 - chanceToClose);
    }
  }
 protected double rankUnfishedCompletable(Completable completable, LegacyAiScoreContext ctx) {
   double rating = 0.0;
   double points = getUnfinishedCompletablePoints(completable, ctx);
   for (Player p : ctx.getMajorOwners()) {
     rating += reducePoints(points, p);
   }
   return rating;
 }
  private double rankTrappedMeeples(LegacyAiScoreContext ctx) {
    // musi tu byt dolni mez - btw nestaci toto misto hodnoceni figurek, spis asi :)

    // TODO lepe
    if (myTurnsLeft < 8) return 0.0;

    if (ctx.getChanceToClose() > 0.4) return 0.0;

    double rating = 0.0;
    for (Meeple m : ctx.getMeeples()) {
      if (isMe(m.getPlayer())) {
        rating += TRAPPED_MY_FIGURE_POINTS;
      } else {
        rating += TRAPPED_ENEMY_FIGURE_POINTS;
      }
    }
    return (1.0 - ctx.getChanceToClose()) * rating; // no reduce
  }
 protected double rankSpecialFigures(LegacyAiScoreContext ctx) {
   double rating = 0.0;
   for (Meeple m : ctx.getSpecialMeeples()) {
     if (m instanceof Builder && isMe(m.getPlayer())) {
       rating += rankBuilder((Builder) m, ctx);
     }
   }
   return rating;
 }
  protected double rankBuilder(Builder builder, LegacyAiScoreContext ctx) {
    if (!ctx.getMajorOwners().contains(getPlayer())) {
      return -3.0; // builder in enemy object penalty
    }
    if (ctx.getChanceToClose() < 0.55) return 0.0;
    double rating = 0.0;
    // builder placed in object
    if (builder.getFeature() instanceof City) {
      rating += 1.5;
    } else {
      rating += 0.5;
    }

    TradersAndBuildersGame tb = getGame().getTradersAndBuildersGame();
    // builder used on object
    if (tb.getBuilderState() == BuilderState.ACTIVATED) {
      rating += 3.5;
    }
    return rating;
  }