BuiltVariant.fromData constructor

BuiltVariant.fromData(
  1. Variant data
)

Implementation

factory BuiltVariant.fromData(Variant data) {
  data = data.normalise();

  Map<int, List<String>> winRegions = {};
  List<PieceDefinition> pieces = [PieceDefinition.empty()];
  Map<String, PieceDefinition> pieceLookup = {};
  Map<String, int> pieceIndexLookup = {};
  List<Action> actions = [...data.actions];
  data.pieceTypes.forEach((s, p) {
    int value = p.royal ? Bishop.mateUpper : p.value;
    if (data.pieceValues?.containsKey(s) ?? false) {
      value = data.pieceValues![s]!;
    }
    PieceDefinition piece = PieceDefinition(type: p, symbol: s, value: value);
    pieces.add(piece);
    pieceLookup[s] = piece;
    int pieceId = pieces.length - 1;
    pieceIndexLookup[s] = pieceId;
    if (p.winRegionEffects.isNotEmpty) {
      List<String> whiteWinRegions = p.winRegionEffects
          .where((e) => e.whiteRegion != null)
          .map((e) => e.whiteRegion!)
          .toList();
      List<String> blackWinRegions = p.winRegionEffects
          .where((e) => e.blackRegion != null)
          .map((e) => e.blackRegion!)
          .toList();
      if (whiteWinRegions.isNotEmpty) {
        winRegions[makePiece(pieceId, Bishop.white)] = whiteWinRegions;
      }
      if (blackWinRegions.isNotEmpty) {
        winRegions[makePiece(pieceId, Bishop.black)] = blackWinRegions;
      }
    }
    actions.addAll(p.actions.map((e) => e.forPieceType(pieceId)));
  });

  Map<ActionEvent, List<Action>> actionsByEvent = {
    for (final e in ActionEvent.values)
      e: actions.where((a) => a.event == e).toList(),
  };

  Map<int, List<int>>? promoMap = {};
  for (final p in pieces.asMap().entries) {
    final promotesTo = p.value.type.promoOptions.promotesTo;
    if (promotesTo == null) continue;
    promoMap[p.key] = promotesTo.map((e) => pieceIndexLookup[e]!).toList();
  }
  if (promoMap.isEmpty) promoMap = null;

  final formatters = [...defaultMoveFormatters];

  BuiltVariant bv = BuiltVariant(
    data: data,
    pieces: pieces,
    pieceLookup: pieceLookup,
    pieceIndexLookup: pieceIndexLookup,
    promotionPieces: pieces
        .asMap()
        .entries
        .where((e) => e.value.type.promoOptions.canPromoteTo)
        .map((e) => e.key)
        .toList(),
    promotablePieces: pieces
        .asMap()
        .entries
        .where((e) => e.value.type.promoOptions.canPromote)
        .map((e) => e.key)
        .toList(),
    promoLimits: data.promotionOptions.pieceLimits
        ?.map((k, v) => MapEntry(pieceIndexLookup[k]!, v)),
    promoMap: promoMap,
    epPiece: data.enPassant
        ? pieces.indexWhere((p) => p.type.enPassantable)
        : Bishop.invalid,
    castlingPiece: data.castling
        ? pieces.indexWhere((p) => p.symbol == data.castlingOptions.rookPiece)
        : Bishop.invalid,
    royalPiece: pieces.indexWhere((p) => p.type.royal),
    materialConditions: data.materialConditions.convert(pieces),
    regions: data.regions.map((k, v) => MapEntry(k, v.build(data.boardSize))),
    winRegions: winRegions,
    actions: actions,
    actionsByEvent: actionsByEvent,
  );

  bv = bv.copyWith(
    firstMoveChecker: data.firstMoveOptions.build(bv),
    stateTransformer: data.stateTransformer?.build(bv),
    moveGenerators: data.moveGenerators.map((e) => e.build(bv)).toList(),
    moveProcessors: Map.fromEntries(
      data.moveProcessors.map((e) => MapEntry(e.type, e.build(bv))),
    ),
    algebraicMoveFormatters: Map.fromEntries(
      formatters.map((e) => MapEntry(e.type, e.algebraic(bv))),
    ),
    prettyMoveFormatters: Map.fromEntries(
      formatters.map((e) => MapEntry(e.type, e.pretty(bv))),
    ),
    promotionBuilder: data.promotionOptions.build(bv),
  );
  // It's like this so the drop builder can depend on the promotion builder.
  bv = bv.copyWith(dropBuilder: data.handOptions.dropBuilder.build(bv));
  bv = bv.copyWith(passChecker: data.passOptions.build(bv));

  return bv;
}