diff --git a/src/App.java b/src/App.java index 0e1c00c..931a8f9 100644 --- a/src/App.java +++ b/src/App.java @@ -23,7 +23,7 @@ private App() { public static String[] sColumnHeadings; public static PrintWriter sWriter; - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { System.out.println("Looking in " + System.getProperty("user.dir") + " for voteTallies.csv"); BufferedReader reader; @@ -43,15 +43,15 @@ public static void main(String[] args) throws IOException { || heading.contains("Full Name")) { continue; } - String position = getElectionNameFromHeading(heading);// remove first/second/third + String election = getElectionNameFromHeading(heading);// remove first/second/third sWriter.println("Found column " + heading); - if (!sAllVotes.containsKey(position)) { - sAllVotes.put(position, new TreeMap<>()); - sWriter.println("Created election " + position); - if (position.contains("Captain")) { - sImportantElections.add(position); - sWriter.println("Important position " + position + " noted"); + if (!sAllVotes.containsKey(election)) { + sAllVotes.put(election, new TreeMap<>()); + sWriter.println("Created election " + election); + if (election.contains("Captain")) { + sImportantElections.add(election); + sWriter.println("Important election " + election + " noted"); } } } @@ -70,6 +70,13 @@ public static void main(String[] args) throws IOException { for (String importantName : sImportantElections) { runElection(importantName); System.out.println("Running election " + importantName); + if (sWinners.containsKey(importantName)) { // a winner has been found so they need to be removed from the + // list of eligible candidates + sAllVotes.keySet().forEach((electionName) -> { + deregisterCandidate(electionName, sWinners.get(importantName)); + }); + + } } for (Map.Entry>> elections : sAllVotes.entrySet()) { @@ -243,4 +250,27 @@ public static SimpleEntry getCurrentLoser(String election) { return new SimpleEntry<>(potentialCurrentLoser, potentialLoserVotes); } + public static void registerCandidate(String electionName, String candidate) { + TreeMap> candidatesForThisElection = sAllVotes.get(electionName); + if (!candidatesForThisElection.containsKey(candidate)) {// candidate not in list for this election + candidatesForThisElection.put(candidate, new ArrayList<>()); + } + } + + public static void deregisterCandidate(String electionName, String candidate) throws Exception { + TreeMap> candidatesVotesForThisElection = sAllVotes.get(electionName); + if (candidatesVotesForThisElection.get(candidate).size() > 0) { + throw new Exception("Trying to deregister candidate " + candidate + " in election " + electionName + + " but they have votes!"); + } + } + + public static boolean isCandidateAvailable(String electionName, String candidate) { + if (!App.sAllVotes.get(electionName).containsKey(candidate)) { + return false; + } + + return true; + } + } \ No newline at end of file diff --git a/src/Ballot.java b/src/Ballot.java index a1ac23b..d839c3d 100644 --- a/src/Ballot.java +++ b/src/Ballot.java @@ -1,36 +1,36 @@ import java.io.IOException; import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.Map; +import java.util.Queue; import java.util.TreeMap; public final class Ballot { - private TreeMap> mVotes = new TreeMap<>();// ballotData + private TreeMap> mVotes = new TreeMap<>();// ballotData private int mBallotIndex; - private TreeMap currentChoiceIdxs = new TreeMap<>(); public Ballot(String ballotLine, int idx) { mBallotIndex = idx; - String[] voteNames = ballotLine.split(",");// chosenCandidates - if (voteNames.length != App.sColumnHeadings.length) { + String[] ballotEntries = ballotLine.split(",");// chosenCandidates + if (ballotEntries.length != App.sColumnHeadings.length) { System.err.println("Length of ballot " + ballotLine + " doesn't match number of elections!"); System.exit(-1); } - for (int columnIdx = 3; columnIdx < voteNames.length; columnIdx++) {// start at 3 to skip timestamp, email, name + for (int columnIdx = 3; columnIdx < ballotEntries.length; columnIdx++) {// start at 3 to skip timestamp, email, + // name String thisColumnHeading = App.sColumnHeadings[columnIdx];// thisColumnString - String thisElection = App.getElectionNameFromHeading(thisColumnHeading); - String thisVote = voteNames[columnIdx];// chosenCandidate + String thisElectionName = App.getElectionNameFromHeading(thisColumnHeading); + String thisChoice = ballotEntries[columnIdx];// chosenCandidate - if (!mVotes.containsKey(thisElection)) {// no votes yet by this ballot for this election - mVotes.put(thisElection, new ArrayList<>()); + if (!mVotes.containsKey(thisElectionName)) {// no votes yet by this ballot for this election + mVotes.put(thisElectionName, new LinkedList<>()); } - if (thisVote.length() > 0) { - TreeMap> candidatesForThisElection = App.sAllVotes.get(thisElection); - if (!candidatesForThisElection.containsKey(thisVote)) {// candidate not in list for this election - candidatesForThisElection.put(thisVote, new ArrayList<>()); - } - ArrayList thisBallotVotesForThisElection = mVotes.get(thisElection); - thisBallotVotesForThisElection.add(thisVote);// better be in order + if (thisChoice.length() > 0) { + App.registerCandidate(thisElectionName, thisChoice); + mVotes.get(thisElectionName).add(thisChoice);// ballot must have numbered choices in order (choice 1 in + // column D, 2 in E, etc.) } } } @@ -38,61 +38,43 @@ public Ballot(String ballotLine, int idx) { @Override public String toString() { StringBuilder rBuilder = new StringBuilder(); - for (Map.Entry> thisElectionChoices : mVotes.entrySet()) { + for (Map.Entry> thisElectionChoices : mVotes.entrySet()) { rBuilder.append("Election " + thisElectionChoices.getKey() + ":"); - for (int i = 0; i < thisElectionChoices.getValue().size(); i++) { - rBuilder.append(" #" + i + "," + thisElectionChoices.getValue().get(i) + "; "); + List listOfChoices = new ArrayList<>(thisElectionChoices.getValue()); + for (int i = 0; i < listOfChoices.size(); i++) { + rBuilder.append(" #" + i + "," + listOfChoices.get(i) + "; "); } } return (rBuilder.toString()); } public boolean cast(String election) throws IOException { - if (!currentChoiceIdxs.containsKey(election)) { - currentChoiceIdxs.put(election, -1); - } - int choice = currentChoiceIdxs.get(election) + 1; - - if (mVotes.get(election).size() <= choice) { + if (mVotes.get(election).size() == 0) { App.sWriter.println( - "Ballot " + mBallotIndex + " thrown away for election " + election + ". Choice " + (choice + 1) - + " not available."); + "Ballot " + mBallotIndex + " thrown away for election " + election + + ". No more choices available."); return false; } - String thisBallotsChoice = mVotes.get(election).get(choice); + String thisBallotsChoice = mVotes.get(election).peek(); - if (!App.sAllVotes.get(election).containsKey(thisBallotsChoice)) { - mVotes.get(election).remove(choice); + if (!App.isCandidateAvailable(election, thisBallotsChoice)) { + mVotes.get(election).poll(); // like pop App.sWriter.println( - "Ballot " + mBallotIndex + " choice #" + (choice + 1) - + " was already eliminated. Moving choices up 1."); + "Ballot " + mBallotIndex + " choice " + thisBallotsChoice + + " is captain or has already been eliminated. Trying next choice."); return cast(election); // now the choice should be valid } ArrayList thisCandidatesBallotList = App.sAllVotes.get(election).get(thisBallotsChoice); - for (String importantElection : App.sImportantElections) { - if (App.sWinners.containsKey(importantElection)) { - if (App.sWinners.get(importantElection).equals(thisBallotsChoice)) { - // this ballot's choice is for someone who already won captain - mVotes.get(election).remove(choice); - App.sWriter.println( - "Ballot " + mBallotIndex + " choice #" + (choice + 1) + " is captain. Moving choices up 1."); - return cast(election); // now the choice should be valid - } - } - } - if (thisCandidatesBallotList.contains(this)) { System.err.println( "Ballot " + mBallotIndex + " already voted for " + thisBallotsChoice + " in election " + election); System.exit(-2); } thisCandidatesBallotList.add(this); - App.sWriter.println("Ballot " + mBallotIndex + " cast for " + thisBallotsChoice + ", choice #" + (choice + 1) - + " in election " + election); - currentChoiceIdxs.put(election, choice); + App.sWriter.println("Ballot " + mBallotIndex + " cast for " + thisBallotsChoice + " in election " + election); return true; }