Last Updated: 2017-12-06 Wed 23:46

CSCI 1103 Project 5: Election!

0.0.1 CODE DISTRIBUTION:

0.0.2 CHANGELOG:

Wed Dec 6 23:34:21 CST 2017
Tests for the project are now available linked from the top of the spec and directly here: p5-tests.zip. Download the testing zip, unzip it, and copy all files into the p5-code project directory. Some of the vote-XXX.txt files may be duplicates but use the new versions in case there have been minor changes over the initial release.
Mon Dec 4 10:43:49 CST 2017
Exception messages for Tally eliminate() have been added to the documentation. They should have the following form:
'Freddie' not in Tally{Francis:0, Claire:0, Heather:0, Viktor:0}

Tally countAll() has been clarified. If any Vote returns null for its best vote, any action may be taken such as raising exceptions or ignoring the vote. This condition will not be tested.

The convention of passing a command line argument to the main() method of Election has been clarified. If no file is named, print a usage message like:

usage: java Election <votes.txt>

1 Introduction

Instant Runoff Voting (IRV) or Ranked Choice Voting (RCV) is a system in which each voter selects ranks candidates for a position according to preference rather than selecting only their first choice. This is the source of the "ranked choice" name. Election results are calculated in rounds in which the candidate with the lowest vote count is dropped. If a voter's first-choice is dropped, their vote moves to their next choice. This is the source of the "instant runoff" name: a runoff election is when low-vote candidates are eliminated and voters choices are restricted. With IRV/RCV run-offs can be done "instantly" based on the rankings of voters.

IRV is generally considered advantageous over other schemes and have started to see use in some local elections including those in local Minnesota elections. It means that voters are free to cast votes for unpopular candidates who strongly align with their views knowing that if their favorite is eliminated, their vote will not be lost but transfer to their next best choice.

A couple videos explaining Ranked Choice Voting:

This project will center on calculating the results of elections which use IRV. It will employ all of the skill that we have studied in Java so far including some new ones.

  • The IRV algorithm is iterative in nature with several termination criteria so looping and conditionals will be essential.
  • Objects and classes will be used to divide up responsibilities such as Vote and Tally along with associated functionality in methods such as countVote().
  • Voting information will be stored in files which must be read to create the necessary internal data.

1.1 Simplified Rules for Ranked Choice Voting

  1. Winners: At any point, if any candidate has more than 50% of the total votes, that candidate is the winner and the results are complete.
  2. Ties: At any point, if all remaining candidates have an equal number of votes there is an all-way tie and the results are complete.
  3. Drop Lowest: If there is not a winner or tie, the candidate(s) with the lowest number of votes are dropped from the election. There may be multiple such candidates. Another round of tallying is done in which votes are recalculated based on the new, smaller pool of candidates.
  4. All Votes Complete: It is assumed that each vote has a complete ordering of the candidates from 1 to N. Additional rules would need to be introduced to deal with partial or improper rankings.

1.2 An Example Election

Four candidates are running for office: Francis, Claire, Heather, and Viktor. There are 12 voters which rank the candidates each as either 1st, 2nd, or 3rd choice according to the rules of IRV.

1.2.1 Round 1 of Tabulating

    RANKS    
Voter Francis Claire Heather Viktor
A 1 4 3 2
B 2 1 3 4
C 3 2 1 4
D 3 2 1 4
E 2 1 3 4
F 1 3 2 4
G 1 2 3 4
H 3 2 1 4
I 2 3 1 4
J 2 4 3 1
K 1 2 3 4
L 2 3 1 4
total 4 2 5 1

While Heather has the most 1st place votes, she does not have a majority so does not yet win the election. Viktor is the candidate with the fewest 1st place votes so is eliminated. Votes are recounted with any voter who chose Viktor as their 1st place (Voter J) selecting their next choice.

1.2.2 Round 2 Tabulating

    RANKS    
        XXX
Voter Francis Claire Heather Viktor
A 1 4 3 2
B 2 1 3 4
C 3 2 1 4
D 3 2 1 4
E 2 1 3 4
F 1 3 2 4
G 1 2 3 4
H 3 2 1 4
I 2 3 1 4
J 2 4 3 1
K 1 2 3 4
L 2 3 1 4
total 5 2 5 XXX

Note that Voter J's vote goes to Francis now as he was 2nd choice after Viktor. Francis and Heather both have 5 votes but this is not a majority. Claire is eliminated with votes to her going to other candidates.

1.2.3 Round 3 Tabulating

    RANKS    
  WINNER XXX   XXX
Voter Francis Claire Heather Viktor
A 1 4 3 2
B 2 1 3 4
C 3 2 1 4
D 3 2 1 4
E 2 1 3 4
F 1 3 2 4
G 1 2 3 4
H 3 2 1 4
I 2 3 1 4
J 2 4 3 1
K 1 2 3 4
L 2 3 1 4
total 7 XXX 5 XXX

The voters who picked Claire as their top choice (Voters B and E) both picked Francis as choice 2 so his votes increase. Francis now has a majority and is the winner of the election. This is despite initially having fewer votes than Heather.

2 Download Code and Setup

As in previous projects, download the code pack linked at the top of the page. Unzip this which will create a folder and create your files in that folder.

File State Notes
Vote.java Create Represents a Vote by a Voter
Tally.java Create Represents a Tally of votes, a partial election result
Util.java Create Utility methods to help parse files and split strings
Election.java Create Provides a main() method to read a vote file and calculate election results
votes-1round.txt Data Votes data with an immediate winner
votes-2waytie.txt Data Votes data with a 2-way tie
votes-3cands.txt Data Votes data with 3 candidates
votes-3waytie.txt Data Votes data with a 3-way tie
votes-5cands.txt Data Votes data with 5 candidates
votes-drop2.txt Data Votes data with 2 lowest vote candidates in a round
votes-many.txt Data Votes data with many candidates
votes-standard.txt Data Votes data with the 4-candidate spec election in it
votes-stress.txt Data Votes data with many candidates and votes
VoteTests.java Testing Tests for the Vote class
TallyTests.java Testing Tests for the Tally class
ElectionTests.java Testing Tests for the Election class
KTests.java Testing Test utilities and run all tests on command line
junit-1103.jar Testing JUnit testing library for command line tests

3 Util Class

Several static text-processing methods are useful elsewhere in the project but do not fill well into any specific class so are housed in the Util class. These are as follows.

3.1 Class Structure of Util

public class Util{
// Contains static methods useful for parsing files.

  public static int countLines(String filename) throws Exception;
  // Count the number of lines in the file given. Makes use of a
  // Scanner to read the file.

  public static String [] splitIntoStrings(String str);
  // Create an array of strings filled with each String in str
  // separated by spaces. Uses a Scanner to parse the String str.
  //
  // For example:
  //
  // String str = "here are some words";
  // String tokens[] = Util.splitIntoStrings(str);
  // tokens is now the array { here, are, some, words }
  //                           0     1    2     3

  public static int [] splitIntoInts(String str);
  // Create an array of ints filled with each integer in str separated
  // by spaces. Uses a Scanner to parse the String str.
  // 
  // String str = "8 6 7 5  30 9";
  // int nums[] = Util.splitIntoInts(str);
  // nums is now the array { 8, 6, 7, 5, 30, 9 }
  //                         0  1  2  3   4  5

}

3.2 Implementation of the Util

3.2.1 Counting File Lines

public class Util{
  public static int countLines(String filename) throws Exception;
}

Make use of a Scanner and a loop involving hasNextLine() and nextLine() to count how many lines are in a file.

Note that you should not use a try/catch block in this method which states in its type signature that it throws Exception. This is a bit similar to a lab 12 problem and just means writing less code

Examples:

> Util.countLines("votes-standard.txt")
13
> Util.countLines("votes-2waytie.txt")
7
> Util.countLines("votes-3waytie.txt")
7
> Util.countLines("votes-drop2.txt")
8
> Util.countLines("not-there.txt")
java.io.FileNotFoundException: not-there.txt (No such file or directory)
	at java.io.FileInputStream.open0(Native Method)
	at java.io.FileInputStream.open(FileInputStream.java:195)
	at java.io.FileInputStream.<init>(FileInputStream.java:138)
	at java.util.Scanner.<init>(Scanner.java:611)
	at Util.countLines(Util.java:10)

3.2.2 Splitting Strings

public class Util{
  public static String [] splitIntoStrings(String str);
  public static int [] splitIntoInts(String str);
}

There are a couple occasions in this project in which it will be necessary to process a line of text read from a file into an array integers or strings. The two methods splitIntoStrings() and splitIntoInts() do this and return arrays of their respective types. A Scanner which reads from the parameter strings should be used for this in two passes

  • First read all tokens in the input string to count them
  • Then allocate an array of the appropriate size
  • Then read back through the tokens in the input string and assign them to elements of the array

The method ARE NOT required to do any error checking (for null strings, for non-numbers, etc.).

Here are examples of the splitting methods from Util shown in DrJava's interactions pane.

Welcome to DrJava
> String s = "Strings to read";
> String arr[] = Util.splitIntoStrings(s);
> arr
{ Strings, to, read }
> String candsStr = "Francis Claire Heather Viktor";
> String cands[] = Util.splitIntoStrings(candsStr);
> cands
{ Francis, Claire, Heather, Viktor }
> String rankStr = "4 2 3 1";
> int ranks[] = Util.splitIntoInts(rankStr);
> ranks
{ 4, 2, 3, 1 }
> int ranks2[] = Util.splitIntoInts("8 5 4 6 1 2 3 7");
> ranks2
{ 8, 5, 4, 6, 1, 2, 3, 7 }
> ranks2[3]
6

3.3 Util Class Manual Inspection Criteria   grading

The criteria below will be examined by graders to account for part of your grade.

Wgt Criteria
2% Good style, indentation, and variable name choices are used. The Camel case naming convention is used. Code is properly indented
3% Scanners and their methods are used to read through files, count tokens, and read tokens.
5% The split() methods use a clearly documented two-pass strategy of counting, the reading tokens into an array.
10% Total weight for these criteria

4 Vote Class

Any election has votes and to accommodate them, the Vote class provides basic facilities to track preferred candidates. In IRV elections, voters must specify a ranking of candidates, a primary feature of the class. Also notable is that, to preserve some semblance of integrity, the Vote class will be immutable: once constructed, it does not change and only has accessor methods.

Very few fields are required for Vote. The instructor implementation of the project uses only one field to keep the ranked candidates. Students may use additional fields if it seems relevant though all fields should be private and documented with their purpose.

4.1 Class Structure of Vote

All the methods in the outline for Vote are required. Note that the private fields have been omitted in the class description but they should be added.

public class Vote{
// A class to represent a ranked ordering of candidates.

  public Vote(String candidates[], int ranks[]);
  // Create a vote. The candidates given are ranked according to the
  // ranks[] parameter.  For example, the parameters
  // 
  //   candidates = {Francis, Claire, Heather, Viktor}; 
  //   ranks      = {2,       3,      0,       1     };
  // 
  // results in the vote
  // 
  //   Vote{Heather, Viktor, Francis, Claire}
  // 
  // where the ordering of the candidates is reflected in the idexes
  // given in ranks[].
  // 

  public String toString();
  // Produce a string representatin of this Vote which shows the
  // ranked ordering of the candidates. The format is as follows.
  //
  // 0 candidates example:
  // Vote{}
  //
  // 4 candidates example:
  // Vote{Heather, Viktor, Francis, Claire}
  //
  // Uses a loop to incrementally build up the string representation.

  public static Vote[] readVoteFile(String filename) throws Exception;
  // Read votes from a file like the following.
  // 
  // Francis Claire Heather Viktor
  // 1 4 3 2
  // 2 1 3 4
  // 3 2 1 4
  //
  // The first line shows the candidates, 4 in this case while each
  // subsequent line are the ranks of those candidates. Returns an
  // array of Vote[] objects initialzied from their contents of the
  // file. Makes use of Scanner and methods of Util the split lines
  // into arrays of strings and integers. Note that each line is
  // 1-indexed so should be decremented to form the ranks of the vote.

  public String getBest(Tally tally);
  // Retrieve the highest ranked candidate for this Vote which is in
  // the Tally given. The parameter tally may contain fewer candidates
  // than were used to create the Vote.  If the Vote has no candidate
  // contained in the given Tally, return null.

}

4.2 Implementation of the Vote Class

4.2.1 Constructor, Fields, toString()

public class Vote{
  public Vote(String candidates[], int ranks[]);
  public String toString();

The constructor for Vote takes an array of candidates and an equal length array of their ranks. During the constructor, a new array of Strings should be allocated for a internal, private field of Vote. Candidates are copied into this array in ranked order and the toString() method produces a string representation of the vote with candidates in ranked order. An example:

Welcome to DrJava. 
> String [] candidates = {"Francis", "Claire", "Heather", "Viktor"}; 
> int ranks[]          = {2,          3,        0,         1      };
> Vote vote = new Vote(candidates, ranks);
> vote.toString()
Vote{Heather, Viktor, Francis, Claire}
> int ranks2[]         = {1,          0,        3,         2      };
> Vote vote2 = new Vote(candidates, ranks2);
> vote2.toString()
Vote{Claire, Francis, Viktor, Heather}

Note that the constructor does no copy the candidates identically but instead arranges its internal array of ranked candidates according to the ranking specified in the ranks[] parameter.

Also note that the ranks are 0-indexed to make creating the internal ranked array of candidates easy.

It is an error to construct a Vote with candidate/rank arrays with differing lengths. A RuntimeException should be thrown with an information error message formatted as follows.

> Vote bad = new Vote(candidates, ranks3);
java.lang.RuntimeException: candidates.length 4 != 2 ranks.length
	at Vote.<init>(Vote.java:25)

It is not specified what should happen if a vote is constructed with bad ranks which are negative, larger than then Lent of candidates, or have repeats in them. In an industrial implementation, checking for these errors and handling them would be important but it is not required here.

4.2.2 Reading Votes from a File

  public static Vote[] readVoteFile(String filename) throws Exception

Votes will be stored in text files necessitating that they be read in. The format of these data files is well represented by the provided votes-standard.txt.

Francis Claire Heather Viktor
1 4 3 2
2 1 3 4
3 2 1 4
3 2 1 4
2 1 3 4
1 3 2 4
1 2 3 4
3 2 1 4
2 3 1 4
2 4 3 1
1 2 3 4
2 3 1 4

The first line contains the names of all candidates while remaining lines contain the ranks of those candidates by each voter. The ranks in data files are 1-indexed so care will need be taken as the Vote class constructor required 0-indexed arrays.

The readVoteFile() method does the following.

  • Takes the name of a vote data file as an argument.
  • Uses a method of Util to count the lines in the file
  • Allocates an array of the correct size to hold all votes in file knowing that the first line does not contain a vote but the candidate list
  • Open the file using a Scanner NOT in a try/catch block
  • Reads the first line and splits it into an array using methods from Util to get the candidates from the file.
  • Proceeds to read each remaining line of the file which is split to produce ranks of the candidates by a voter and creates a Vote object which is put into the array
  • Closes the file and returns the array of votes
  • No exceptions are caught or thrown in the method explicitly; instead any exceptions that result percolate up as indicated by the throws Exception in the type signature of the method.

Example of calling the readVoteFile() is below.

> Vote [] standard = Vote.readVoteFile("votes-standard.txt");
> standard.length
12
> standard
{Vote{Francis, Viktor, Heather, Claire},
 Vote{Claire, Francis, Heather, Viktor},
 Vote{Heather, Claire, Francis, Viktor},
 Vote{Heather, Claire, Francis, Viktor},
 Vote{Claire, Francis, Heather, Viktor},
 Vote{Francis, Heather, Claire, Viktor},
 Vote{Francis, Claire, Heather, Viktor},
 Vote{Heather, Claire, Francis, Viktor},
 Vote{Heather, Francis, Claire, Viktor},
 Vote{Viktor, Francis, Heather, Claire},
 Vote{Francis, Claire, Heather, Viktor},
 Vote{Heather, Francis, Claire, Viktor} }

> Vote [] tie = Vote.readVoteFile("votes-2waytie.txt");
> tie.length
6
> tie
{Vote{Viktor, Heather, Claire, Francis},
 Vote{Viktor, Heather, Claire, Francis},
 Vote{Viktor, Heather, Claire, Francis},
 Vote{Claire, Heather, Viktor, Francis},
 Vote{Claire, Heather, Viktor, Francis},
 Vote{Claire, Heather, Viktor, Francis} }

4.2.3 getBest() Candidate

  public String getBest(Tally tally)

IRV elections require that a vote must provide its "best" candidate of a specified number available. This will be done by an interaction vbetween the Vote and Tally classes. A Tally keeps track of which candidates remain after some are eliminated and the Vote will be required to produces which candidate is considered best in its ranking among those that remain.

> String [] candidates = {"Francis", "Claire", "Heather", "Viktor"}; 
> int ranks[]          = {2,          3,        0,         1      };
> Vote vote = new Vote(candidates, ranks);
> Tally tally1 = new Tally(candidates);
> tally1
Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
> vote
Vote{Heather, Viktor, Francis, Claire}

> vote.getBest(tally1)          
Heather                         // top candidate available

> String [] candidates2 = {"Francis", "Claire", "Viktor"};
> Tally tally2 = new Tally(candidates2);
> tally2
Tally{Francis:0, Claire:0, Viktor:0}
> vote
Vote{Heather, Viktor, Francis, Claire}
> vote.getBest(tally2)
Viktor                          // Heather gone, 2nd choice Viktor

> String [] candidates3 = {"Francis", "Claire"};
> Tally tally3 = new Tally(candidates3);
> tally3
Tally{Francis:0, Claire:0}
> vote.getBest(tally3)
Francis                         // top 2 gone, Francis ranked next

> Tally tally4 = new Tally(new String[]{"Freddy","Remy"});
> tally4
Tally{Freddy:0, Remy:0}
> vote
Vote{Heather, Viktor, Francis, Claire}
> vote.getBest(tally4)          // No candidates preferred available
null                            // return null - something is likely wrong

This method will require some parts of Tally to be complete it may be wise to work on that class and then return to Vote when it is suitable. In particular, the contains() method of Tally is useful if used in a loop in getBest() over the candidates in order of rank.

4.3 Vote Class Manual Inspection Criteria   grading

The criteria below will be examined by graders to account for part of your grade.

Wgt Criteria
3% Good style, indentation, and variable name choices are used. The Camel case naming convention is used. Code is properly indented
2% Fields of the class are private and fields/methods are non-static.
3% The readVoteFile() is clearly laid out and has comments describing what is happening.
2% readVoteFile() makes use of the methods from the Util class to count file lines and split lines.
10% Total weight for these criteria

5 Tally Class Overview

Elections need results to be calculated which is the responsibility of the Tally class. It represents a set of candidates and their current count of votes. Unlike the Vote class, Tally is somewhat mutable: it has methods which alter its internal state such as countVote(). It also has a method called eliminate() used to produce a new tally with one candidate eliminated. These methods will all see use in performing election calculations.

5.1 Class Structure of Tally

Below are all of the public methods that should appear in the class. The private fields do not appear but should be added.

public class Tally{
// Represent the candidates in election along with the counts of the
// votes for each of them.

  public Tally(String candidates[]);
  // Construct a Tally with the given candidates. The constructor
  // makes a deep copy of the array given so that subsequent changes
  // to the parameter array do not affect the tally.  The initial vot
  // counts for each candidate are all 0.

  public String toString();
  // Produce a string version of the Tally formatted as follows.
  // 
  // 0 candidates
  // Tally{}
  //
  // 3 candidates
  // Tally{Francis:4, Claire:2, Heather:4}
  //
  // Builds the string reprsentation up incrementally using a loop.

  public int size();
  // Return the number of candidates in this Tally.

  public boolean contains(String candidate);
  // Return true if the specified candidate is present in this Tally
  // and false otherwise.

  public void countVote(String candidate);
  // Increment the vote count of the candidate specified. The the
  // candidate is not present in this Tally, throw a RuntimeException
  // with a message formatted like:
  //
  // 'Edmond' not in Tally{Francis:0, Claire:0, Heather:1, Viktor:0}

  public int totalVotes();
  // Return the total number of votes which have been counted in this
  // Tally.

  public String outputString();
  // Produce a nicely formatted table of the Tally. The table includes
  // vote count, percent, and name for each candidate which appears
  //
  // CNT     % NAME
  //   4  33.3 Francis
  //   2  16.7 Claire
  //   5  41.7 Heather
  //   1   8.3 Viktor
  //
  // The format string "%3d %5.1f %s\n" is useful where the arguments
  // are the vote counts, percentage of votes won, and candidate
  // names.

  public String getWinner();
  // Calculate the percent of the total votes each candidate has
  // earned. If any candidate has greater than 50% of the votes,
  // return that candidate as a String. If no candidate has more than
  // 50% of the vote, return null.

  public String [] getMinCandidates();
  // Return an array of Strings containing all candidate names which
  // are tied for the minimum number of votes.  First searche for the
  // minimum vote count in the Tally among candidates, the allocates
  // an array of Strings of that size and fills it with candidates
  // which have vote counts equal to the minimum.

  public boolean allWayTie();
  // Return true if an all-way tie has occurred and false
  // otherwise. This happens if all candidates have an equal number of
  // votes. Note that all-way ties correspond with getMinCanidates()
  // producing an array with equal length to the size() of the
  // tally.

  public Tally eliminate(String candidate);
  // Create a new Tally with the candidate specified eliminated. This
  // Tally should have 1 fewer candidates.  The vote counts for each
  // candidate in the resulting ballot shoudl be 0. If the candidate
  // mentioned is not in the Tally, throw a RuntimeException with the
  // message:
  //
  // 'Freddie' not in Tally{Francis:0, Claire:0, Heather:0, Viktor:0}

  public static Tally readTallyFromFile(String filename) throws Exception;
  // Read candidate names from the first line of the given file and
  // create a Tally from them. The initial vote counts for each of
  // candidate are 0. Makes use of Scanner and the
  // Util.splitIntoStrings() method.  This method may throw Exceptions
  // and should not use a try/catch block.

  public String countAll(Vote votes[]);
  // Count all of the votes in the given array and add them to the
  // counts of votes in this tally. Each vote has its best remaining
  // candidate added to the tally.  While tabulating, create a
  // transcript String of the process which shows what is done for
  // each vote. This string has the following format
  //
  //  0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Claire:0, Heather:0}
  //  1 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:1, Heather:0}
  // ...
  //  9 : Francis    Vote{Viktor, Francis, Heather, Claire} Tally{Francis:4, Claire:2, Heather:4}
  // 10 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:5, Claire:2, Heather:4}
  // 11 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:5, Claire:2, Heather:5}
  // 
  // for which the following format string is useful:
  //   "%2d : %-10s %s %s\n"
  // arguments are the vote index, best candidate, vote toString(), and tally toString().
  //
  // If any Vote returns null, the behavior of this method is NOT
  // DEFINED. Any action may be taken such as printing a warning,
  // throwing an exception or ignoring the vote. No tests will be run
  // on this case.

}

5.2 Implementation of Tally

5.2.1 Constructor, Fields, size(), toString(), contains()

public class Tally{
  public Tally(String candidates[]);
  public String toString();
  public boolean contains(String candidate);
}

Tally will need a least a couple fields to track the candidates on the tally and their respective counts of votes. Students may add additional fields as the need arises. All fields should be private. Only the candidates are passed to the constructor while the vote counts should default to 0 for all candidates. The size() method returns how many candidates are associated with the tally.

The toString() method should produce a string that combines the candidate names and counts in a similar format to Vote.

Finally, Tally provides a way to determine whether a candidate is present or absent from its roster of candidates via the contains(cand) method. True or false is returned based on whether the named candidate is among those tracked by the tally.

Below are examples of calling the constructor, toString(), and contains().

> String cands[] = { "Francis", "Claire", "Heather", "Viktor" };
> Tally tally1 = new Tally(cands);
> tally1.toString()
Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
> tally1.size()
4
> tally1.contains("Heather")
true
> tally1.contains("Claire")
true
> tally1.contains("Freddy")
false
> tally1.contains("Remy")
false

> String none[] = {};
> Tally tally0 = new Tally(none);
> tally0.toString()
Tally{}
> tally0.size()
0
> tally0.contains("Viktor")
false
> tally0.contains("Francis")
false

> String lots [] = {"A","B","C","D","E","F","G","H"};
> Tally tally3 = new Tally(lots);
> tally3.toString()
Tally{A:0, B:0, C:0, D:0, E:0, F:0, G:0, H:0}
> tally3.size()
8
> tally3.contains("B")
true
> tally3.contains("G")
true
> tally3.contains("Z")
false
> tally3.contains("Francis")
false

5.2.2 countVote(), totalVotes(), outputString()

  public void countVote(String candidate);
  public int totalVotes();
  public String outputString();

Counting votes is essential to the purpose of Tally and is done via the countVote(cand) method. This method increases the named candidate's vote count by 1 and will be used in conjunction with the vote.getBest(tally) method to select a favored candidate to increase.

The total votes cast for all candidates so far will be needed at various points which is produced by totalVotes(). It sums all votes and returns the total.

Finally, a read out of the current state of the tally in tabular format is produced by the outputString(). This method creates somewhat more verbose output than toString() which shows candidate standings. An example table table:

CNT     % NAME
  4  33.3 Francis
  2  16.7 Claire
  5  41.7 Heather
  1   8.3 Viktor

Demonstrations of the above methods.

> String cands[] = { "Francis", "Claire", "Heather", "Viktor" };
> Tally tally1 = new Tally(cands);
> tally1
Tally{Francis:0, Claire:0, Heather:0, Viktor:0}

> tally1.countVote("Claire");
> tally1.countVote("Heather");
> tally1.countVote("Heather");
> tally1.countVote("Viktor");
> tally1.countVote("Francis");
> tally1.countVote("Heather");
> tally1.countVote("Francis");
> tally1.totalVotes()
7
> tally1.toString()
Tally{Francis:2, Claire:1, Heather:3, Viktor:1}
> tally1.outputString()
CNT     % NAME
  2  28.6 Francis
  1  14.3 Claire
  3  42.9 Heather
  1  14.3 Viktor
> tally1.countVote("Francis");
> tally1.countVote("Claire");
> tally1.totalVotes()
9
> tally1.outputString()
CNT     % NAME
  3  33.3 Francis
  2  22.2 Claire
  3  33.3 Heather
  1  11.1 Viktor

// Throw RuntimeExceptions when a candidate is not present in a call to countVote()
> tally1.countVote("Freddie");
java.lang.RuntimeException: 'Freddie' not in Tally{Francis:3, Claire:2, Heather:3, Viktor:1}
	at Tally.countVote(Tally.java:73)

5.2.3 Winners

  public String getWinner();

According to our rules for IRV elections, a winner can be declared if any candidate has more than 50% of the counted votes. The getWinner() method should analyze the internal counts of votes for a Tally and determine this. Should a candidate have greater than 50% of the vote, getWinner() should return the candidate as a string. It may happen that no candidate has sufficient votes to be the winner in which case null is returned. Here are examples.

> tally1.outputString()
CNT     % NAME
  3  33.3 Francis
  2  22.2 Claire
  3  33.3 Heather
  1  11.1 Viktor

> tally1.getWinner()
null                            // no one has a majority yet
> tally1.countVote("Heather")
> tally1.countVote("Heather")
> tally1.countVote("Heather")
> tally1.outputString()
CNT     % NAME
  3  25.0 Francis
  2  16.7 Claire
  6  50.0 Heather               // Heather is close but no above 50%
  1   8.3 Viktor

> tally1.getWinner()
null                            // no winner yet
> tally1.countVote("Heather")
> tally1.outputString()
CNT     % NAME
  3  23.1 Francis
  2  15.4 Claire
  7  53.8 Heather               // above 50%
  1   7.7 Viktor

> tally1.getWinner()
Heather                         // winner, winner, chicken dinner

// stuff the ballot box
> for(int i=0; i<10; i++){ tally1.countVote("Francis"); }
> tally1.outputString()
CNT     % NAME
 13  56.5 Francis               // winners are not permanent...
  2   8.7 Claire
  7  30.4 Heather
  1   4.3 Viktor

> tally1.getWinner()
Francis                         // house of cards complete

5.2.4 Losers and Ties

  public String [] getMinCandidates();
  public boolean allWayTie();

As there are winners, there are also losers in the elections. IRV elections focuses on dropping candidates with low vote counts. There may be several such candidates. All of them are reported by the getMinCandidates() which returns an array of the candidates who have the lowest vote counts. Often this will be a single candidate but there may be more.

> tally.outputString()
CNT     % NAME
  2  13.3 Francis
  4  26.7 Claire
  4  26.7 Heather
  5  33.3 Viktor

> String mins[] = tally.getMinCandidates();
> mins
{ Francis }                     // single minimum candidate

// adjust the votes
> for(int i=0; i<6; i++){ tally.countVote("Francis"); }
> tally.outputString()
CNT     % NAME
  8  38.1 Francis
  4  19.0 Claire                // tied for last
  4  19.0 Heather               // tied for last
  5  23.8 Viktor

> String mins[] = tally.getMinCandidates();
> mins
{ Claire, Heather }             // two minimum candidates

It is possible that the election may result in an all-way tie. This occurs when the remaining candidates all have the same number of votes. Conveniently, since all candidates are tied, they all have the minimum number of votes so a convenient mechanism to detect all-way ties is to compare the size of the candidates with minimum votes to the size of all the candidates. There are also other ways to determine whether an all-way tie has occurred.

The allWayTie() method returns true if an tie has occurred and false otherwise.

> tally.outputString()
CNT     % NAME
  8  38.1 Francis               // clear winnner
  4  19.0 Claire
  4  19.0 Heather
  5  23.8 Viktor

> tally.allWayTie()             // no tie at present
false

// Adjust vote counts
> for(int i=0; i<4; i++){ tally.countVote("Claire"); }
> for(int i=0; i<4; i++){ tally.countVote("Heather"); }
> for(int i=0; i<3; i++){ tally.countVote("Viktor"); }

> tally.outputString()
CNT     % NAME
  8  25.0 Francis               // all even now
  8  25.0 Claire
  8  25.0 Heather
  8  25.0 Viktor

> tally.allWayTie()             // allWayTie() has occurred
true

5.2.5 Eliminating Candidates

  public Tally eliminate(String candidate);

IRV elections happen in automatic rounds. At the end of each round, the candidates with minimum votes are dropped. To facilitate this, the Tally class provides the eliminate(cand) method. This method takes the interesting tack of producing a fresh new Tally with the requested candidate dropped. The new Tally is distinct from the original with a smaller size and 0 vote counts. The original Tally is disconnected from it.

To complete this method, create a new String array and copy in all candidates save for the candidate to eliminate. The call the Tally() constructor to create a fresh tally with the smaller candidate roster and return it.

If the candidate requested in the drop is not present, throw a RuntimeException with a message formatted as indicated.

> original.toString()
Tally{Francis:2, Claire:7, Heather:5, Viktor:3}    // 4 candidates originally
> Tally dropped1 = original.eliminate("Viktor");   // drop 1 candidate
> dropped1.toString()                              // new Tally has fewer candidates
Tally{Francis:0, Claire:0, Heather:0}              // and has counts reset to 0
> dropped1.countVote("Claire")
> dropped1.toString()
Tally{Francis:0, Claire:1, Heather:0}              // new Tally is independent from original
> original.toString()
Tally{Francis:2, Claire:7, Heather:5, Viktor:3}    // same vote counts in original
> Tally dropped2 = dropped1.eliminate("Francis");  // drop a second candidate, get another Tally
> dropped2.toString()
Tally{Claire:0, Heather:0}                         // also has counts reset to 0
> dropped2.contains("Remy")
false                                              // when called with a non-existen candidate
> dropped2.eliminate("Remy")                       // eliminate() throws a RuntimeException
java.lang.RuntimeException: No candidate 'Remy' in Tally{Claire:0, Heather:0}
	at Tally.eliminate(Tally.java:181)

5.2.6 Reading a Tally from a File

  public static Tally readTallyFromFile(String filename) throws Exception;

It is necessary in the main election algorithm to initialize a Tally based on the contents of voter files. This should be done by opening the file and reading the first line of the file which contains the candidates. This line can be split using methods from the Util class. The remainder of the file is ignored by this method.

Since it is static, this method has a different calling convention that uses the class name to invoke it.

> Tally tally = Tally.readTallyFromFile("votes-standard.txt")
> tally.toString()
Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
> Tally many = Tally.readTallyFromFile("votes-many.txt");
> many.toString()
Tally{A:0, B:0, C:0, D:0, E:0, F:0, G:0, H:0}

5.2.7 Transcripts of Counting all Votes

  public String countAll(Vote votes[])

The primary concern of Tally is to count votes which come in batches. The countAll(votes) method will loop through the given array and of votes and count all of them. Importantly, this is where the vote.getBest(tally) method should be used so that if the first choice mentioned in a vote is not present in the given Tally, a lower ranked choice can be gotten.

Calls to vote.getBest(tally) require an instance of a Tally to produce their best candidate. Since countAll() is a non-static method, such a reference is available via the this pointer.

The return value of the transcript should be a String which shows how each vote was counted. The format of each line shown below and is similar to the following.

 0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Claire:0, Heather:0, Viktor:0}
 1 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:1, Heather:0, Viktor:0}
 2 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:1, Viktor:0}
 3 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:2, Viktor:0}
 4 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:2, Heather:2, Viktor:0}
...
  • Vote index in array (indexed from 0)
  • Vote toString()
  • Tally toString() after dding the best available candidate for the vote.

A good way to build up the string is via String.format() and string concatenation.

Here are examples of the method.

> Tally tally = Tally.readTallyFromFile("votes-standard.txt")
> tally.toString()
Tally{Francis:0, Claire:0, Heather:0, Viktor:0}

> Vote votes[] = Vote.readVoteFile("votes-standard.txt");
> votes
{ Vote{Francis, Viktor, Heather, Claire},
  Vote{Claire, Francis, Heather, Viktor},
  Vote{Heather, Claire, Francis, Viktor},
  Vote{Heather, Claire, Francis, Viktor},
  Vote{Claire, Francis, Heather, Viktor},
  Vote{Francis, Heather, Claire, Viktor},
  Vote{Francis, Claire, Heather, Viktor},
  Vote{Heather, Claire, Francis, Viktor},
  Vote{Heather, Francis, Claire, Viktor},
  Vote{Viktor, Francis, Heather, Claire},
  Vote{Francis, Claire, Heather, Viktor},
  Vote{Heather, Francis, Claire, Viktor} }

> String transcript = tally.countAll(votes);

> tally.toString()
Tally{Francis:4, Claire:2, Heather:5, Viktor:1}

> tally.outputString()
CNT     % NAME
  4  33.3 Francis
  2  16.7 Claire
  5  41.7 Heather
  1   8.3 Viktor

> transcript
 0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Claire:0, Heather:0, Viktor:0}
 1 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:1, Heather:0, Viktor:0}
 2 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:1, Viktor:0}
 3 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:2, Viktor:0}
 4 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:2, Heather:2, Viktor:0}
 5 : Francis    Vote{Francis, Heather, Claire, Viktor} Tally{Francis:2, Claire:2, Heather:2, Viktor:0}
 6 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Claire:2, Heather:2, Viktor:0}
 7 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:3, Claire:2, Heather:3, Viktor:0}
 8 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:3, Claire:2, Heather:4, Viktor:0}
 9 : Viktor     Vote{Viktor, Francis, Heather, Claire} Tally{Francis:3, Claire:2, Heather:4, Viktor:1}
10 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:4, Claire:2, Heather:4, Viktor:1}
11 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:4, Claire:2, Heather:5, Viktor:1}

5.3 Tally Class Manual Inspection Criteria   grading

The criteria below will be examined by graders to account for part of your grade.

Wgt Criteria
2% Fields of the class are private and each method has the correct static/non-static designator
3% Good style, indentation, and variable name choices are used. The Camel case naming convention is used. Code is properly indented
2% Brief but sufficient comments are supplied to indicate what is happening. Comments that appear in the specification do not count.
5% getMinCandidate() is clearly laid out: determine the minimum count, count candidates with the minimum, add them to an array.
5% eliminate() has a clear loop which passes over the candidate which should be eliminated.
3% readTallyFromFile() uses Scanner appropriately to parse the first line for the candidates
20% Total weight for these criteria

6 Election Class

The Election class ties all of the parts together. Its main() method reads a file of votes, allocates an initial tally, and then starts calculating results. Each result is checked for winner or tie and if neither occurs, minimum candidates are dropped and another round of voting is performed.

6.1 Class Structure of Election

Below are all of the public methods that should appear in the class. The private fields do not appear but should be added.

public class Election{
// Contains a main method to tabulate the results of an election based
// on votes stored in text files.

  public static void main(String args[]) throws Exception;
  // Read a vote file named on the command line such as
  // votes-standard.txt.  Creates a Tally and repeatedly eliminate
  // minimum vote candidates until either a winner is found or an
  // all-way-tie occurs. Prints the results of each round of vote
  // calculation.
  // 
  // The vote file should be specified on the command line in runs like this:
  //
  // $> java Election votes-standard.txt
  // 
  // If no, vote file is specified, main() should print a usage
  // message message:
  // 
  // $> java Election
  // usage: java Election <votes.txt>
  //
  // and return immediately.

}

6.2 Implementation of Election

6.2.1 main() Method and command line arguments

The main() method should accept a command line argument which is the name of a vote file. Several of these are provided as sample data. This allows one to run the election program on the command line or in DrJava's interactions pane on different vote results.

> java Election votes-standard.txt
...
> java Election votes-2waytie.txt
...
> java Election votes-many.txt
...

6.2.2 Algorithm for Running election

The main algorithm for running the entire election shoudl run something like the following.

read TALLY from given file
read VOTES[] from the given file
report how many votes have been read
loop while no winner/tie has been found {
  print the round number (starting with round 1), remaining candidates, and TALLY
  count all the votes for TALLY and get its TRANSCRIPT
  print the TRANSCRIPT
  check for a winner: print and finish if there is one
  check for a tie: print and finish if there is one
  determine the minimum vote candidates and eliminate them to create a new TALLY
  increase the voting round and repeat
}

Study the sample sessions below to determine the approximate format for the output.

6.3 Election Class Manual Instances Criteria   grading

Wgt Criteria
2% Good style, indentation, and variable name choices are used. The Camel case naming convention is used. Code is properly indented
3% Brief but sufficient comments are supplied to indicate what is happening. Comments that appear in the specification do not count.
5% The flow of control is clear as to which part of the election is being performed at each step.
10% Total weight for these criteria

6.4 Sample Session

> java Election votes-standard.txt 
votes-standard.txt : 12 votes read
Round 1 : 4 candidates Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
Transcript:
 0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Claire:0, Heather:0, Viktor:0}
 1 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:1, Heather:0, Viktor:0}
 2 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:1, Viktor:0}
 3 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:2, Viktor:0}
 4 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:2, Heather:2, Viktor:0}
 5 : Francis    Vote{Francis, Heather, Claire, Viktor} Tally{Francis:2, Claire:2, Heather:2, Viktor:0}
 6 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Claire:2, Heather:2, Viktor:0}
 7 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:3, Claire:2, Heather:3, Viktor:0}
 8 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:3, Claire:2, Heather:4, Viktor:0}
 9 : Viktor     Vote{Viktor, Francis, Heather, Claire} Tally{Francis:3, Claire:2, Heather:4, Viktor:1}
10 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:4, Claire:2, Heather:4, Viktor:1}
11 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:4, Claire:2, Heather:5, Viktor:1}

CNT     % NAME
  4  33.3 Francis
  2  16.7 Claire
  5  41.7 Heather
  1   8.3 Viktor

1 minimum vote candidates
Eliminating: Viktor

Round 2 : 3 candidates Tally{Francis:0, Claire:0, Heather:0}
Transcript:
 0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Claire:0, Heather:0}
 1 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:1, Heather:0}
 2 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:1}
 3 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:1, Claire:1, Heather:2}
 4 : Claire     Vote{Claire, Francis, Heather, Viktor} Tally{Francis:1, Claire:2, Heather:2}
 5 : Francis    Vote{Francis, Heather, Claire, Viktor} Tally{Francis:2, Claire:2, Heather:2}
 6 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Claire:2, Heather:2}
 7 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:3, Claire:2, Heather:3}
 8 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:3, Claire:2, Heather:4}
 9 : Francis    Vote{Viktor, Francis, Heather, Claire} Tally{Francis:4, Claire:2, Heather:4}
10 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:5, Claire:2, Heather:4}
11 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:5, Claire:2, Heather:5}

CNT     % NAME
  5  41.7 Francis
  2  16.7 Claire
  5  41.7 Heather

1 minimum vote candidates
Eliminating: Claire

Round 3 : 2 candidates Tally{Francis:0, Heather:0}
Transcript:
 0 : Francis    Vote{Francis, Viktor, Heather, Claire} Tally{Francis:1, Heather:0}
 1 : Francis    Vote{Claire, Francis, Heather, Viktor} Tally{Francis:2, Heather:0}
 2 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:2, Heather:1}
 3 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:2, Heather:2}
 4 : Francis    Vote{Claire, Francis, Heather, Viktor} Tally{Francis:3, Heather:2}
 5 : Francis    Vote{Francis, Heather, Claire, Viktor} Tally{Francis:4, Heather:2}
 6 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:5, Heather:2}
 7 : Heather    Vote{Heather, Claire, Francis, Viktor} Tally{Francis:5, Heather:3}
 8 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:5, Heather:4}
 9 : Francis    Vote{Viktor, Francis, Heather, Claire} Tally{Francis:6, Heather:4}
10 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:7, Heather:4}
11 : Heather    Vote{Heather, Francis, Claire, Viktor} Tally{Francis:7, Heather:5}

CNT     % NAME
  7  58.3 Francis
  5  41.7 Heather

WINNER: Francis
> java Election votes-1round.txt 
votes-1round.txt : 7 votes read
Round 1 : 4 candidates Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
Transcript:
 0 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:1, Claire:0, Heather:0, Viktor:0}
 1 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:2, Claire:0, Heather:0, Viktor:0}
 2 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Claire:0, Heather:0, Viktor:0}
 3 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:4, Claire:0, Heather:0, Viktor:0}
 4 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:4, Claire:0, Heather:0, Viktor:1}
 5 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:4, Claire:0, Heather:0, Viktor:2}
 6 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Francis:4, Claire:1, Heather:0, Viktor:2}

CNT     % NAME
  4  57.1 Francis
  1  14.3 Claire
  0   0.0 Heather
  2  28.6 Viktor

WINNER: Francis
> java Election votes-2waytie.txt
votes-2waytie.txt : 6 votes read
Round 1 : 4 candidates Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
Transcript:
 0 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:0, Claire:0, Heather:0, Viktor:1}
 1 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:0, Claire:0, Heather:0, Viktor:2}
 2 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:0, Claire:0, Heather:0, Viktor:3}
 3 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Francis:0, Claire:1, Heather:0, Viktor:3}
 4 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Francis:0, Claire:2, Heather:0, Viktor:3}
 5 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Francis:0, Claire:3, Heather:0, Viktor:3}

CNT     % NAME
  0   0.0 Francis
  3  50.0 Claire
  0   0.0 Heather
  3  50.0 Viktor

2 minimum vote candidates
Eliminating: Francis
Eliminating: Heather

Round 2 : 2 candidates Tally{Claire:0, Viktor:0}
Transcript:
 0 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Claire:0, Viktor:1}
 1 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Claire:0, Viktor:2}
 2 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Claire:0, Viktor:3}
 3 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Claire:1, Viktor:3}
 4 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Claire:2, Viktor:3}
 5 : Claire     Vote{Claire, Heather, Viktor, Francis} Tally{Claire:3, Viktor:3}

CNT     % NAME
  3  50.0 Claire
  3  50.0 Viktor

ALL WAY TIE BETWEEN:
Claire
Viktor
> java Election votes-drop2.txt 
votes-drop2.txt : 7 votes read
Round 1 : 4 candidates Tally{Francis:0, Claire:0, Heather:0, Viktor:0}
Transcript:
 0 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:1, Claire:0, Heather:0, Viktor:0}
 1 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:2, Claire:0, Heather:0, Viktor:0}
 2 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Claire:0, Heather:0, Viktor:0}
 3 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:3, Claire:0, Heather:0, Viktor:1}
 4 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:3, Claire:0, Heather:0, Viktor:2}
 5 : Heather    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:3, Claire:0, Heather:1, Viktor:2}
 6 : Heather    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:3, Claire:0, Heather:2, Viktor:2}

CNT     % NAME
  3  42.9 Francis
  0   0.0 Claire
  2  28.6 Heather
  2  28.6 Viktor

1 minimum vote candidates
Eliminating: Claire

Round 2 : 3 candidates Tally{Francis:0, Heather:0, Viktor:0}
Transcript:
 0 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:1, Heather:0, Viktor:0}
 1 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:2, Heather:0, Viktor:0}
 2 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3, Heather:0, Viktor:0}
 3 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:3, Heather:0, Viktor:1}
 4 : Viktor     Vote{Viktor, Heather, Claire, Francis} Tally{Francis:3, Heather:0, Viktor:2}
 5 : Heather    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:3, Heather:1, Viktor:2}
 6 : Heather    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:3, Heather:2, Viktor:2}

CNT     % NAME
  3  42.9 Francis
  2  28.6 Heather
  2  28.6 Viktor

2 minimum vote candidates
Eliminating: Heather
Eliminating: Viktor

Round 3 : 1 candidates Tally{Francis:0}
Transcript:
 0 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:1}
 1 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:2}
 2 : Francis    Vote{Francis, Claire, Heather, Viktor} Tally{Francis:3}
 3 : Francis    Vote{Viktor, Heather, Claire, Francis} Tally{Francis:4}
 4 : Francis    Vote{Viktor, Heather, Claire, Francis} Tally{Francis:5}
 5 : Francis    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:6}
 6 : Francis    Vote{Heather, Viktor, Claire, Francis} Tally{Francis:7}

CNT     % NAME
  7 100.0 Francis

WINNER: Francis
> java Election votes-many.txt 
votes-many.txt : 20 votes read
Round 1 : 8 candidates Tally{A:0, B:0, C:0, D:0, E:0, F:0, G:0, H:0}
Transcript:
 0 : D          Vote{D, G, B, A, E, C, F, H} Tally{A:0, B:0, C:0, D:1, E:0, F:0, G:0, H:0}
 1 : H          Vote{H, D, C, B, A, G, F, E} Tally{A:0, B:0, C:0, D:1, E:0, F:0, G:0, H:1}
 2 : A          Vote{A, E, G, C, H, B, F, D} Tally{A:1, B:0, C:0, D:1, E:0, F:0, G:0, H:1}
 3 : E          Vote{E, A, D, G, C, B, H, F} Tally{A:1, B:0, C:0, D:1, E:1, F:0, G:0, H:1}
 4 : C          Vote{C, F, A, B, E, H, D, G} Tally{A:1, B:0, C:1, D:1, E:1, F:0, G:0, H:1}
 5 : H          Vote{H, A, G, D, E, F, B, C} Tally{A:1, B:0, C:1, D:1, E:1, F:0, G:0, H:2}
 6 : A          Vote{A, F, D, E, B, H, C, G} Tally{A:2, B:0, C:1, D:1, E:1, F:0, G:0, H:2}
 7 : D          Vote{D, E, A, H, G, C, F, B} Tally{A:2, B:0, C:1, D:2, E:1, F:0, G:0, H:2}
 8 : H          Vote{H, F, C, D, B, A, E, G} Tally{A:2, B:0, C:1, D:2, E:1, F:0, G:0, H:3}
 9 : B          Vote{B, G, F, C, D, E, H, A} Tally{A:2, B:1, C:1, D:2, E:1, F:0, G:0, H:3}
10 : C          Vote{C, A, D, H, B, F, G, E} Tally{A:2, B:1, C:2, D:2, E:1, F:0, G:0, H:3}
11 : C          Vote{C, B, E, G, H, A, F, D} Tally{A:2, B:1, C:3, D:2, E:1, F:0, G:0, H:3}
12 : F          Vote{F, A, E, D, B, G, C, H} Tally{A:2, B:1, C:3, D:2, E:1, F:1, G:0, H:3}
13 : E          Vote{E, B, D, F, C, G, H, A} Tally{A:2, B:1, C:3, D:2, E:2, F:1, G:0, H:3}
14 : A          Vote{A, B, D, E, G, F, H, C} Tally{A:3, B:1, C:3, D:2, E:2, F:1, G:0, H:3}
15 : H          Vote{H, F, C, B, D, G, E, A} Tally{A:3, B:1, C:3, D:2, E:2, F:1, G:0, H:4}
16 : H          Vote{H, F, B, D, C, A, G, E} Tally{A:3, B:1, C:3, D:2, E:2, F:1, G:0, H:5}
17 : D          Vote{D, A, C, G, H, E, F, B} Tally{A:3, B:1, C:3, D:3, E:2, F:1, G:0, H:5}
18 : D          Vote{D, G, H, E, B, A, C, F} Tally{A:3, B:1, C:3, D:4, E:2, F:1, G:0, H:5}
19 : E          Vote{E, C, D, A, G, B, F, H} Tally{A:3, B:1, C:3, D:4, E:3, F:1, G:0, H:5}

CNT     % NAME
  3  15.0 A
  1   5.0 B
  3  15.0 C
  4  20.0 D
  3  15.0 E
  1   5.0 F
  0   0.0 G
  5  25.0 H

1 minimum vote candidates
Eliminating: G

Round 2 : 7 candidates Tally{A:0, B:0, C:0, D:0, E:0, F:0, H:0}
Transcript:
 0 : D          Vote{D, G, B, A, E, C, F, H} Tally{A:0, B:0, C:0, D:1, E:0, F:0, H:0}
 1 : H          Vote{H, D, C, B, A, G, F, E} Tally{A:0, B:0, C:0, D:1, E:0, F:0, H:1}
 2 : A          Vote{A, E, G, C, H, B, F, D} Tally{A:1, B:0, C:0, D:1, E:0, F:0, H:1}
 3 : E          Vote{E, A, D, G, C, B, H, F} Tally{A:1, B:0, C:0, D:1, E:1, F:0, H:1}
 4 : C          Vote{C, F, A, B, E, H, D, G} Tally{A:1, B:0, C:1, D:1, E:1, F:0, H:1}
 5 : H          Vote{H, A, G, D, E, F, B, C} Tally{A:1, B:0, C:1, D:1, E:1, F:0, H:2}
 6 : A          Vote{A, F, D, E, B, H, C, G} Tally{A:2, B:0, C:1, D:1, E:1, F:0, H:2}
 7 : D          Vote{D, E, A, H, G, C, F, B} Tally{A:2, B:0, C:1, D:2, E:1, F:0, H:2}
 8 : H          Vote{H, F, C, D, B, A, E, G} Tally{A:2, B:0, C:1, D:2, E:1, F:0, H:3}
 9 : B          Vote{B, G, F, C, D, E, H, A} Tally{A:2, B:1, C:1, D:2, E:1, F:0, H:3}
10 : C          Vote{C, A, D, H, B, F, G, E} Tally{A:2, B:1, C:2, D:2, E:1, F:0, H:3}
11 : C          Vote{C, B, E, G, H, A, F, D} Tally{A:2, B:1, C:3, D:2, E:1, F:0, H:3}
12 : F          Vote{F, A, E, D, B, G, C, H} Tally{A:2, B:1, C:3, D:2, E:1, F:1, H:3}
13 : E          Vote{E, B, D, F, C, G, H, A} Tally{A:2, B:1, C:3, D:2, E:2, F:1, H:3}
14 : A          Vote{A, B, D, E, G, F, H, C} Tally{A:3, B:1, C:3, D:2, E:2, F:1, H:3}
15 : H          Vote{H, F, C, B, D, G, E, A} Tally{A:3, B:1, C:3, D:2, E:2, F:1, H:4}
16 : H          Vote{H, F, B, D, C, A, G, E} Tally{A:3, B:1, C:3, D:2, E:2, F:1, H:5}
17 : D          Vote{D, A, C, G, H, E, F, B} Tally{A:3, B:1, C:3, D:3, E:2, F:1, H:5}
18 : D          Vote{D, G, H, E, B, A, C, F} Tally{A:3, B:1, C:3, D:4, E:2, F:1, H:5}
19 : E          Vote{E, C, D, A, G, B, F, H} Tally{A:3, B:1, C:3, D:4, E:3, F:1, H:5}

CNT     % NAME
  3  15.0 A
  1   5.0 B
  3  15.0 C
  4  20.0 D
  3  15.0 E
  1   5.0 F
  5  25.0 H

2 minimum vote candidates
Eliminating: B
Eliminating: F

Round 3 : 5 candidates Tally{A:0, C:0, D:0, E:0, H:0}
Transcript:
 0 : D          Vote{D, G, B, A, E, C, F, H} Tally{A:0, C:0, D:1, E:0, H:0}
 1 : H          Vote{H, D, C, B, A, G, F, E} Tally{A:0, C:0, D:1, E:0, H:1}
 2 : A          Vote{A, E, G, C, H, B, F, D} Tally{A:1, C:0, D:1, E:0, H:1}
 3 : E          Vote{E, A, D, G, C, B, H, F} Tally{A:1, C:0, D:1, E:1, H:1}
 4 : C          Vote{C, F, A, B, E, H, D, G} Tally{A:1, C:1, D:1, E:1, H:1}
 5 : H          Vote{H, A, G, D, E, F, B, C} Tally{A:1, C:1, D:1, E:1, H:2}
 6 : A          Vote{A, F, D, E, B, H, C, G} Tally{A:2, C:1, D:1, E:1, H:2}
 7 : D          Vote{D, E, A, H, G, C, F, B} Tally{A:2, C:1, D:2, E:1, H:2}
 8 : H          Vote{H, F, C, D, B, A, E, G} Tally{A:2, C:1, D:2, E:1, H:3}
 9 : C          Vote{B, G, F, C, D, E, H, A} Tally{A:2, C:2, D:2, E:1, H:3}
10 : C          Vote{C, A, D, H, B, F, G, E} Tally{A:2, C:3, D:2, E:1, H:3}
11 : C          Vote{C, B, E, G, H, A, F, D} Tally{A:2, C:4, D:2, E:1, H:3}
12 : A          Vote{F, A, E, D, B, G, C, H} Tally{A:3, C:4, D:2, E:1, H:3}
13 : E          Vote{E, B, D, F, C, G, H, A} Tally{A:3, C:4, D:2, E:2, H:3}
14 : A          Vote{A, B, D, E, G, F, H, C} Tally{A:4, C:4, D:2, E:2, H:3}
15 : H          Vote{H, F, C, B, D, G, E, A} Tally{A:4, C:4, D:2, E:2, H:4}
16 : H          Vote{H, F, B, D, C, A, G, E} Tally{A:4, C:4, D:2, E:2, H:5}
17 : D          Vote{D, A, C, G, H, E, F, B} Tally{A:4, C:4, D:3, E:2, H:5}
18 : D          Vote{D, G, H, E, B, A, C, F} Tally{A:4, C:4, D:4, E:2, H:5}
19 : E          Vote{E, C, D, A, G, B, F, H} Tally{A:4, C:4, D:4, E:3, H:5}

CNT     % NAME
  4  20.0 A
  4  20.0 C
  4  20.0 D
  3  15.0 E
  5  25.0 H

1 minimum vote candidates
Eliminating: E

Round 4 : 4 candidates Tally{A:0, C:0, D:0, H:0}
Transcript:
 0 : D          Vote{D, G, B, A, E, C, F, H} Tally{A:0, C:0, D:1, H:0}
 1 : H          Vote{H, D, C, B, A, G, F, E} Tally{A:0, C:0, D:1, H:1}
 2 : A          Vote{A, E, G, C, H, B, F, D} Tally{A:1, C:0, D:1, H:1}
 3 : A          Vote{E, A, D, G, C, B, H, F} Tally{A:2, C:0, D:1, H:1}
 4 : C          Vote{C, F, A, B, E, H, D, G} Tally{A:2, C:1, D:1, H:1}
 5 : H          Vote{H, A, G, D, E, F, B, C} Tally{A:2, C:1, D:1, H:2}
 6 : A          Vote{A, F, D, E, B, H, C, G} Tally{A:3, C:1, D:1, H:2}
 7 : D          Vote{D, E, A, H, G, C, F, B} Tally{A:3, C:1, D:2, H:2}
 8 : H          Vote{H, F, C, D, B, A, E, G} Tally{A:3, C:1, D:2, H:3}
 9 : C          Vote{B, G, F, C, D, E, H, A} Tally{A:3, C:2, D:2, H:3}
10 : C          Vote{C, A, D, H, B, F, G, E} Tally{A:3, C:3, D:2, H:3}
11 : C          Vote{C, B, E, G, H, A, F, D} Tally{A:3, C:4, D:2, H:3}
12 : A          Vote{F, A, E, D, B, G, C, H} Tally{A:4, C:4, D:2, H:3}
13 : D          Vote{E, B, D, F, C, G, H, A} Tally{A:4, C:4, D:3, H:3}
14 : A          Vote{A, B, D, E, G, F, H, C} Tally{A:5, C:4, D:3, H:3}
15 : H          Vote{H, F, C, B, D, G, E, A} Tally{A:5, C:4, D:3, H:4}
16 : H          Vote{H, F, B, D, C, A, G, E} Tally{A:5, C:4, D:3, H:5}
17 : D          Vote{D, A, C, G, H, E, F, B} Tally{A:5, C:4, D:4, H:5}
18 : D          Vote{D, G, H, E, B, A, C, F} Tally{A:5, C:4, D:5, H:5}
19 : C          Vote{E, C, D, A, G, B, F, H} Tally{A:5, C:5, D:5, H:5}

CNT     % NAME
  5  25.0 A
  5  25.0 C
  5  25.0 D
  5  25.0 H

ALL WAY TIE BETWEEN:
A
C
D
H

7 Automatic Testing (50%)   grading

7.1 Running Tests

Run the tests associated with the project and ensure all of them pass. This can be done in DrJava by pressing the Test button when test files are open.

On the command line you can run all tests with the following commands.

On Unix/Mac platforms, use a terminal to run the following commands in the folder where your code exists.

> javac -cp .:junit-1103.jar KTests.java   #compile
> java -cp .:junit-1103.jar KTests         #run tests

On windows, use cmd.exe and change to the correct directory. Run the commands below where which use a semicolon (;) rather than a colon (:).

> javac -cp .;junit-1103.jar KTests.java   #compile
> java -cp .;junit-1103.jar KTests         #run tests

Correctly passing all tests will yield output similar to the following.

JUnit version 4.12
..........
Time: 0.024

OK (10 tests)

Failing some tests will yield long messages which hint at where there might be a problem. Failures always end with the number of tests passed/failed as in the following.

FAILURES!!!
Tests run: 10,  Failures: 5

7.2 Test Grading Policies

Some policies to keep in mind with respect to how automatic tests affect grades.

  • Credit on this section is proportional to the number of tests passed.
  • If there were 30 total tests for the project…
  • Passing 30 / 30 tests gets 30 / 30 * 50 = 50.00
  • Passing 15 / 30 tests gets 15 / 30 * 50 = 25.00
  • Passing 4 / 30 tests gets 4 / 30 * 50 = 6.67
  • A 5% penalty may be deducted from this portion if code does not compile initially but a grader is able to quickly fix the problem.
  • Passing no tests because code does not compile or does not work properly gets 0 credit.

8 Zip and Submit

8.1 Submit to Canvas

Once your are confident your code is working, you are ready to submit. Ensure your folder has all of the required files. Create a zip archive of your lab folder and submit it to blackboard.

On Canvas:

  • Click on the Assignments section
  • Click on the appropriate link for this lab
  • Scroll down to "Attach a File"
  • Click "Browse My Computer"
  • Select you Zip file and press OK

8.2 Late Policies

You may wish to review the policy on late project submission which will cost you late tokens to submit late or credit if you run out of tokens. No projects will be accepted more than 48 hours after the deadline.

http://www-users.cs.umn.edu/~kauffman/1103/syllabus.html#late-projects


Author: Chris Kauffman (kauffman@umn.edu)
Date: 2017-12-06 Wed 23:46