Beispiel #1
0
        ///<summary>
        /// Candidates are lowercase letters.
        /// Utility may be positional or explicit.
        /// Positional utility groups candidates into space-separated buckets, assigning utility 100 to the first bucket and utility 0 to omitted candidates. Buckets in between are evenly pro-rated.
        /// Buckets prefixed by an integer and a colon assign that integer utility to the bucket, overriding any positional utility.
        ///</summary>
        public static Voter Parse(int candidateCount, string voter)
        {
            var buckets   = voter.Split(' ', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);
            var utilities = new int[candidateCount];

            for (var i = 0; i < buckets.Length; i++)
            {
                var match = Regex.Match(buckets[i], @"^(-?\d*):?([a-z]+)$");

                if (!match.Success)
                {
                    throw new InvalidOperationException($"Unexpected bucket format '{buckets[i]}'.");
                }

                var utility = int.TryParse(match.Groups[1].Value, out var parsed)
                    ? parsed
                    : BucketDefaultUtility(i, buckets.Length);

                foreach (var c in match.Groups[2].Value)
                {
                    utilities[ParsingUtility.DecodeCandidateIndex(c)] = utility;
                }
            }

            return(new Voter(utilities));
        }
        ///<summary>
        /// Comparers are separated by newlines or semicolons.
        /// Candidates are lowercase letters.
        /// Comparers may be duplicated by suffixing the line with "* nn", where "nn" is a positive integer.
        ///</summary>
        public static CandidateComparerCollection <T> Parse(string source, int?candidateCount = null)
        {
            candidateCount ??= ParsingUtility.CandidateCount(source);
            if (candidateCount < 2)
            {
                throw new InvalidOperationException("Unexpected number of candidates.");
            }

            return(new CandidateComparerCollection <T>(
                       candidateCount.Value,
                       source
                       .Split(new char[] { '\n', ';' }, StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
                       .Select(line =>
            {
                var starSplit = line.Split('*', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

                if (starSplit.Length > 2)
                {
                    throw new InvalidOperationException($"Unexpected number of *s on line '{line}'.");
                }

                return (
                    Comparer: ParseComparer(candidateCount.Value, starSplit[0]),
                    Count: starSplit.Length == 2
                                ? int.Parse(starSplit[1])
                                : 1);
            })
                       .ToCountedList()));
        }
Beispiel #3
0
        public override string ToString()
        {
            var numberOfBuckets = Ranking.Count - (Utilities.Any(u => u == 0) ? 1 : 0);

            return(Ranking
                   .Where(candidates => Utilities[candidates[0]] != 0)
                   .Select((candidates, bucketNumber) =>
                           BucketDefaultUtility(bucketNumber, numberOfBuckets) == Utilities[candidates[0]]
                        ? ParsingUtility.EncodeCandidates(candidates)
                        : Utilities[candidates[0]].ToString() + ParsingUtility.EncodeCandidates(candidates))
                   .Join(" "));
        }