Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- {
- "posttype":"droop",
- "numberofseats":"3",
- "candidates" : ["Turtle","Gorilla","Monkey","Tiger","Leopard","Lynx"],
- "votes":
- [
- ["Leopard","Lynx","Tiger","Monkey"],
- ["Lynx","Leopard","Tiger"],
- ["Lynx"],
- ["Monkey","Tiger","Leopard"],
- ["Tiger","Monkey","Gorilla","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger"],
- ["Turtle","Gorilla"],
- ["Monkey","Gorilla","Tiger"],
- ["Monkey","Gorilla","Leopard"],
- ["Monkey","Leopard","Tiger"],
- ["Monkey","Leopard","Gorilla"],
- ["Monkey","Lynx","Turtle"],
- ["Monkey","Turtle","Tiger"],
- ["Monkey","Leopard","Tiger"],
- ["Monkey","Gorilla","Tiger"],
- ["Monkey","Gorilla","Tiger"],
- ["Monkey","Turtle","Tiger"],
- ["Monkey","Turtle","Tiger"],
- ["Monkey","Lynx","Tiger"],
- ["Tiger","Monkey","Gorilla"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"],
- ["Gorilla","Turtle","Monkey","Tiger","Leopard"]
- ]
- }
- */
- using Newtonsoft.Json;
- using System;
- using System.Collections.Generic;
- using System.IO;
- using System.Linq;
- using System.Text;
- using System.Threading.Tasks;
- namespace STV
- {
- class JSONElectionInformation
- {
- public string posttype { get; set; }
- public uint numberofseats { get; set; }
- public List<string> candidates { get; set; }
- public List<List<string>> votes { get; set; }
- }
- class Vote
- {
- public Vote(List<string> candidates,ICollection<string> votes)
- {
- Weight = 1m;
- IEnumerable<uint> indexlist = from i in votes select (uint)candidates.IndexOf(i);
- this.Ranks = new List<uint>(indexlist);
- }
- public decimal Weight { get; set; }
- public List<uint> Ranks { get; set; }
- public String ToString()
- {
- return String.Format("[{0} -> {1}]", Weight, String.Join(",", Ranks));
- }
- }
- class Program
- {
- static void Main(string[] args)
- {
- string input = File.ReadAllText(args[0]);
- // Grab all my info from the specified JSON file
- JSONElectionInformation fileinfo = JsonConvert.DeserializeObject<JSONElectionInformation>(input);
- List<Vote> votes = (from i in fileinfo.votes select new Vote(fileinfo.candidates, i)).ToList();
- uint seatsrequired = fileinfo.numberofseats;
- // check to see if we specified droop or hare method
- decimal votesrequired = fileinfo.posttype == "droop" ?
- ((decimal)votes.Count / ((decimal)seatsrequired + 1)) + 1 : // droop (votes/(seats+1) + 1)
- ((decimal)votes.Count / ((decimal)seatsrequired)); // default is hare (votes/seats)
- List<uint> chosenseats = new List<uint>();
- // while we still need to elect some people....
- while (chosenseats.Count < seatsrequired)
- {
- // cull anyone who no longer votes for a candidate or whos vote carries no weight
- votes.RemoveAll(i => i.Ranks.Count == 0 || i.Weight == 0);
- // seperate all our votes into the dictionary based on who each persons (current) first choice is.
- Dictionary<uint, List<Vote>> splitvotes = new Dictionary<uint, List<Vote>>();
- foreach (Vote v in votes)
- {
- uint choice = v.Ranks.First();
- if (splitvotes.ContainsKey(choice))
- splitvotes[choice].Add(v);
- else
- splitvotes.Add(choice, new List<Vote> { v });
- }
- // if we have as many candidates as we have seats, we're done. Just elect them all.
- if (splitvotes.Count == (seatsrequired - chosenseats.Count))
- {
- foreach (uint i in splitvotes.Keys)
- chosenseats.Add(i);
- break;
- }
- // check for any people that meet or exceed the total number of votes needed
- List<uint> elected = (from i in splitvotes where i.Value.Sum(x => x.Weight) >= votesrequired select i.Key).ToList();
- if(elected.Count != 0){
- foreach (uint candidate in elected)
- {
- // proportionally redistribute excess votes - We're using the "everybody votes again at a fraction of a normal vote"
- // method rather than any random vote selection process
- decimal exceeded = splitvotes[candidate].Sum(x => x.Weight) - votesrequired;
- decimal multiplier = ((decimal)exceeded / (decimal)splitvotes[candidate].Count);
- foreach (Vote v in splitvotes[candidate])
- v.Weight *= multiplier;
- // since the candidates already elected, remove all references to them in the ranking.
- foreach (Vote v in votes)
- v.Ranks.RemoveAll(i => i == candidate);
- chosenseats.Add(candidate);
- }
- }
- // If we have more candidates with votes than we have seats, we need to eliminate someone.
- else if (splitvotes.Count > (seatsrequired - chosenseats.Count))
- {
- // TODO: what to do if two people tie in total votes? Randomly choose one of them?
- uint loser = splitvotes.OrderBy(x => x.Value.Sum( vote => vote.Weight)).First().Key;
- // eliminate the loser - remove all references to them in the ranking
- foreach (Vote v in votes)
- v.Ranks.RemoveAll(i => i == loser);
- }
- else
- {
- // TODO: What happens if no one wants more people? Not sure...
- break;
- }
- }
- Console.WriteLine(String.Join(",", from i in chosenseats select fileinfo.candidates[(int)i]));
- Console.ReadLine();
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement