IrvElection<TCandidate extends Comparable> constructor

IrvElection<TCandidate extends Comparable>(
  1. List<RankedBallot<TCandidate>> ballots, {
  2. Iterable<TCandidate>? candidates,
})

Implementation

factory IrvElection(
  List<RankedBallot<TCandidate>> ballots, {
  Iterable<TCandidate>? candidates,
}) {
  final ballotCandidates = ballots.expand((b) => b.rank).toSet();

  final candidateSet =
      candidates == null ? ballotCandidates : candidates.toSet();

  assert(
    candidates == null || candidateSet.containsAll(ballotCandidates),
    'If `candidates` is provided, then every candidate in `ballots` should '
    'exist in `candidates`.',
  );

  final rounds = <IrvRound<TCandidate>>[];

  IrvRound<TCandidate> round;
  final eliminatedCandidates = <TCandidate>{};
  do {
    round = IrvRound<TCandidate>(
      rounds.length + 1,
      ballots,
      eliminatedCandidates,
    );
    rounds.add(round);
    eliminatedCandidates.addAll(round.eliminatedCandidates);
  } while (!round.isFinal);

  final candidatesInRounds = <TCandidate>{};
  final places = <ElectionPlace<TCandidate>>[];
  for (var round in rounds.reversed) {
    for (var roundPlace in round.places) {
      final copy = roundPlace.toList()
        ..removeWhere(places.expand((candidate) => candidate).contains);

      if (copy.isNotEmpty) {
        candidatesInRounds.addAll(copy);
        final place =
            places.isEmpty ? 1 : places.last.place + places.last.length;
        places.add(ElectionPlace(place, copy));
      }
    }
  }

  final remaining = candidateSet.difference(candidatesInRounds);
  if (remaining.isNotEmpty) {
    places.add(ElectionPlace(
      places.last.place + places.last.length,
      remaining.toList(growable: false),
    ));
  }
  return IrvElection._internal(
    candidateSet.toList(growable: false),
    ballots,
    places,
    rounds,
  );
}