CS 149: Programming Fundamentals
James Madison University, Spring 2018 Semester

PA4: Fairly Odd Election (Loops and Arrays)


Image Credit: DeviantArt.com

Objectives

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.

  1. 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.

  2. 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.

  3. 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.

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.

  1. public void testCountPopular()- Test for popular election winners
  2. public void testCountOdd() - Test for winners because of odd votes and votes that end with a 5
  3. public void testCountEvenOdder() - Test for winners because of even votes and votes that end with a 4
  4. public void testRandomCounts()- Test several arrays of various sizes using very different random seeds
  5. public void testNegative() - Test sending negative array values to each of the four methods
  6. public 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:

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:

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.

You may (and should) revise your test cases in your final submission.