James Madison University, Spring 2018 Semester
PA4: Fairly Odd Election (Loops and Arrays)
Image Credit:
DeviantArt.com
Objectives
- Develop JUnit tests before writing the program.
- Write loops that contain nested if-else statements.
- Pass arrays as method arguments and return values.
- Manipulate, copy, and compare arrays of numbers.
- Generate random numbers based on an algorithm.
Honor Code
This assignment must be completed individually. Your submission must conform to the JMU Honor Code. Authorized help is limited to general discussion on Piazza, the lab assistants assigned to CS 139/149, and the instructor. Copying work from another student or the Internet is an honor code violation and will be grounds for a reduced or failing grade in the course.
Background
Election season is upon us, and many people don't realize just how involved computers, algorithms, and network security are in this process. While we won't get into all the details here, you might check out the wikipedia article on electronic voting. Also of interest is the humanitarian open source software project Ushahidi which develops crowdsourcing tools and began in response to post-election violence in Kenya in 2008.
But on with our own election tools! The CS 149 election is certainly rigged -- and may become even more crazy. The leaders involved want to compare strategies and have asked you to implement several ballot counting approaches as outlined below. Some of them are "fairly odd".
You will implement these approaches in separate methods in a class called Election
. Each method will be passed a parameter of an array of votes and will return an integer corresponding to the index of the array representing the winner of the election. You will also need to write JUnit tests that "cover" (execute) 100% of your statements. These will be in a class called ElectionTest
.
Getting Started
You will not be given any starting files for this assignment. You should create two files, Election.java
and ElectionTest.java
. Election.java
should contain all of the counting methods and the random counts method as described below. ElectionTest.java
should include the six JUnit test methods explained below.
JUnit is the way to "run" this assignment. However, you may create an ElectionDriver
to test the use of the methods in a main application, though this is not required.
As you work on the assignment, you may find it useful to reuse existing methods and/or implement additional methods to simplify your code. Feel free to add new methods to Election.java
, but do NOT change the design of any of the provided methods.
Counting Methods
For each counting method, you will be passed an array of integer values representing the vote counts for each candidate (votes[i]
is the number of votes for candidate i
). You should return the index of the winning candidate.
public static int countPopular(int[] votes)
Popular vote - the candidate with the highest number of votes wins. Return the index of the winning candidate or -1 to indicate an invalid election in the case of inappropriate vote counts or ties.- Example: given the votes {10, 20, 30, 40, 50},
countPopular
should return 4. public static int countOdd(int[] votes)
Odd - all candidates with an "odd" number of votes get their vote count doubled, unless the count ends with the digit 5. Once all vote counts are manipulated, the winner is determined by popular vote.- Example: given the votes {4, 6, 7, 8, 10},
countOdd
should return 2. public static int countEvenOdder(int[] votes)
Even Odder - all candidates with an even number of votes gets their vote count doubled, unless the count ends in a 4, in which case 10 is subtracted from the vote count. Once all vote counts are manipulated, the winner is determined by popular vote.- Example: given the votes {1, 5, 7, 8, 9},
countEvenOdder
should return 3.
In addition, your counting methods should check the vote values to make sure that they are reasonable. If any are negative, your counting methods should return -1. Don't forget to test these cases too!
Since arrays are reference types, it is important that none of your methods change the contents of parameters. Doing so will corrupt data in your test methods and may cause them to fail. If you ever need to change array values, make a copy of the array first.
Random Counts Method
Your "count" methods support any number of candidates, so it will be fun to test them with a variety of scenarios! You are to implement a method named public static int[] randomCounts(int candidates, int voters, long seed)
that generates an array of vote counts, given the number of candidates, the number of voters, and a seed for the random number generator. The seed is necessary for testing with JUnit — since the numbers are only pseudorandom, we can determine exactly what array the method will return.
Here is the algorithm for generating votes: For each candidate, generate a random number between 0 and 1. Multiply this "percentage" by the number of voters, and round the result to the nearest integer. Assign this number of votes to the current candidate, and then decrease the number of voters. Do not generate a random percentage for the final candidate; they should get 100% of the remaining votes. Note that randomCounts
should return null
if candidates or voters is negative.
For example, consider the test case randomCounts(3, 100, 0)
. Given the seed value of 0, Random.nextDouble()
returns the values 0.730967787376657, 0.24053641567148587, and so forth. So the first candidate should get 73 of the votes (0.730967787376657 * 100), and there are 27 votes remaining. The second candidate gets 6 of the votes (0.24053641567148587 * 27), leaving the remaining 21 votes for the third and final candidate. So the expected result array is {73, 6, 21}
.
Test Methods
You should implement ElectionTest.java
first, before you start working on Election.java
. Each of the following test methods should include multiple assertEquals
and/or assertArrayEquals
statements. For example, you should test whether your solution works regardless of where the winning candidate is located in the array.
public void testCountPopular()
- Test for popular election winnerspublic void testCountOdd()
- Test for winners because of odd votes and votes that end with a 5public void testCountEvenOdder()
- Test for winners because of even votes and votes that end with a 4public void testRandomCounts()
- Test several arrays of various sizes using very different random seedspublic void testNegative()
- Test sending negative array values to each of the four methodspublic void testTiesInvalid()
- Test for ties between winning and losing candidates
Finally, your ElectionTest.java
must compile and run against the instructor's solution, pass Checkstyle without any errors, and include proper documentation comments.
Submission
Part A (30 pts): Due Friday, Mar 2 at 11:00 PM
Rubric for Part A:
- 3 pts each test: 18 pts
- Checkstyle: 4 pts
- JavaDoc comments: 4 pts
- Compiles and runs: 4 pts
Submit only your JUnit tests (ElectionTest.java
) via Web-CAT.
Late work will not be accepted. If you do not complete Part A by Friday 03/02, you will receive a zero for Part A.
Part B (70 pts): Due Friday, Mar 16 at 11:00 PM
Rubric for Entire Assignment:
- Part A (see details above): 30 pts
- Part B Checkstyle (WebCAT): 8 pts
- Part B Correctness (WebCAT): 42 pts
- Part B Code Quality(Instructor): 20 pts
Combine your Election.java
and ElectionTest.java
into a zip file, and submit via Web-CAT. Do not include any other files in your zip archive. There will be no Canvas submission for this assignment.
- -15% on Saturday, Mar 17
- -30% on Sunday, Mar 18
- Not accepted afterwards
You may (and should) revise your test cases in your final submission.