I'm having trouble with getting Runoff to complete Check50. All checks are passing except the two below for the print_winner function
:( print_winner prints name when someone has a majority
Cause print_winner did not print winner of election
:( print_winner returns true when someone has a majority
Cause print_winner did not print winner and then return true
I can't figure out what the issue is as my manual testing shows the correct candidate as winner. I think there must be some edge case where it's not correctly identifying the winner however I can't think of it
eg:
./runoff Alice Bob Charlie
Number of voters: 5
Rank 1: Alice
Rank 2: Charlie
Rank 3: Bob
Rank 1: Alice
Rank 2: Charlie
Rank 3: Bob
Rank 1: Bob
Rank 2: Charlie
Rank 3: Alice
Rank 1: Bob
Rank 2: Charlie
Rank 3: Alice
Rank 1: Charlie
Rank 2: Alice
Rank 3: Bob
Alice
My code is below, if anyone could point me in the right direction regards to a mistake in my logic or a test case I should try to find the bug(s) I'd really appreciate it. Also - Is there any way to see more information on what check50 is trying to help with debugging? Thanks
#include <cs50.h>
#include <stdio.h>
#include <string.h>
// Max voters and candidates
#define MAX_VOTERS 100
#define MAX_CANDIDATES 9
// preferences[i][j] is jth preference for voter i
int preferences[MAX_VOTERS][MAX_CANDIDATES];
// Candidates have name, vote count, eliminated status
typedef struct
{
string name;
int votes;
bool eliminated;
}
candidate;
// Array of candidates
candidate candidates[MAX_CANDIDATES];
// Numbers of voters and candidates
int voter_count;
int candidate_count;
//int min;
int votecount;
string currentcandidate;
double winningtally;
string winrar;
// Function prototypes
bool vote(int voter, int rank, string name);
void tabulate(void);
bool print_winner(void);
int find_min(void);
bool is_tie(int min);
void eliminate(int min);
//argc determines the number of arguments requested from the user
//argv stands for argument values
int main(int argc, string argv[])
{
// Check for invalid usage
//if less than 2 arguments are made on the command line print message and exit
//argc == arg count
if (argc < 2)
{
printf("Usage: runoff [candidate ...]\n");
//exit program
//return 1 in the main function means that the program does not execute successfully and there is some error
return 1;
}
// Populate array of candidates
// each candidate is an argument word. 1 is subtracted to take out the ./command word
candidate_count = argc - 1;
//if too many candidates (arguments) are entered by the user return an error message
if (candidate_count > MAX_CANDIDATES)
{
printf("Maximum number of candidates is %i\n", MAX_CANDIDATES);
//return error code 2
return 2;
}
//create the appropriate number of candidates based on candidate_count (taken from arguments)
for (int i = 0; i < candidate_count; i++)
{
// first argument is name 1. then loop i to pickup other names too
candidates[i].name = argv[i + 1];
//set votes default to 0
candidates[i].votes = 0;
//set all candidates as not eliminated to start
candidates[i].eliminated = false;
}
//ask user for number of voters
voter_count = get_int("Number of voters: ");
//if more voters set than max number (100 set using #define at the top) then print an error message to user
if (voter_count > MAX_VOTERS)
{
printf("Maximum number of voters is %i\n", MAX_VOTERS);
//return error code 3 - to differentiate different errors when debugging.
//any value returned other than 0 means something was wrong,
//so set different numbers throughout to differentiate which one went wrong
return 3;
}
// Keep querying for votes
//loop asking for vote until voter count is reached
for (int i = 0; i < voter_count; i++)
{
// Query for each rank
//loop asking for each voters rank until they have voted for each candidate
for (int j = 0; j < candidate_count; j++)
{
string name = get_string("Rank %i: ", j + 1);
// Record vote, unless it's invalid
//if they input a name that doesnt match a candidate then inform the user the vote was wasted/not counted
//if !vote means if vote returns false. if vote() would mean if vote returns true.
//seems like this type of if statement still runs the vote process
if (!vote(i, j, name))
{
printf("Invalid vote.\n");
//return error code 4
return 4;
}
}
printf("\n");
}
// Keep holding runoffs until winner exists
while (true)
{
// Calculate votes given remaining candidates
//run the tabulate function
tabulate();
// Check if election has been won
//create bool variable - and set it whether print winner returned true or false when ran
bool won = print_winner();
//if won = true then 'break' the loop
if (won)
{
break;
}
// Eliminate last-place candidates
//create min integer which holds the value of the minimum number of votes any candidate has in this round
int min = find_min();
//create bool variable and set it to whether true or false
//which is determined by whether the is_tie function
//says there is a tie or not using the min value of minimum votes
//(ie - if all remaining candidates have the min number of votes, set to true)
bool tie = is_tie(min);
// If tie, everyone wins
//if tie = true then print all remaining candidate names
if (tie)
{
//loop through all candidates
for (int i = 0; i < candidate_count; i++)
{
//if a candidate.eliminated is false, print their name
if (!candidates[i].eliminated)
{
printf("Tied winner: %s\n", candidates[i].name);
}
}
//break loop
break;
}
// Eliminate anyone with minimum number of votes
//run the eliminate function at the end of the round to take out any candidates that have the
//min number of votes
eliminate(min);
// Reset vote counts back to zero
//loops through eacg candidate to set their votes to 0 for next round of counting
for (int i = 0; i < candidate_count; i++)
{
candidates[i].votes = 0;
}
//TBR!!!
printf("Recount, votes reset to 0\n");
}
// return 0 means application executed successfully
return 0;
}
// Record preference if vote is valid
//vote is either true or false (return true or false to main function where vote function was called)
bool vote(int voter, int rank, string name)
{
// TODO
//#### FROM PLURALITY
int votetrueorfalse = 0;
for (int i = 0; i < candidate_count; i++)
{
currentcandidate = candidates[i].name;
if (strcmp(name, currentcandidate) == 0)
{
preferences[voter][rank] = i;
votetrueorfalse = 1;
}
}
//END PLURALITY
if (votetrueorfalse == 0)
{
return false;
}
else
{
return true;
}
}
// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
//preferences[voter][vote rank] e.g. voter 2, vote rank 3 is second candidate => preferences[1][2] = 1
// TODO
//check first preference, if not eliminated then add vote for that candidate
//if first preference is eliminated check 2nd preference and loop
//check first candidate - eliminated true or false.
//loop through each voter
for (int i = 0; i < voter_count; i++)
{
//create an int to hold voters preference of candidate
int chosencandidate;
int k = 0;
chosencandidate = preferences[i][k];
while (candidates[chosencandidate].eliminated == true)
{
k++;
chosencandidate = preferences[i][k];
}
//set the int to the value of candidate (candidate 1 / candidate 2 / candidate 3)
//if that candidate hasnt been eliminated, increase that candidates vote count by 1
candidates[chosencandidate].votes++;
//TBR
printf("vote for %s, tally is %i\n", candidates[chosencandidate].name, candidates[chosencandidate].votes);
}
return;
}
// Print the winner of the election, if there is one
bool print_winner(void)
{
// TODO
int winner = 0;
//check first candidate number of votes. if greater than half the votes - then print name and return true
//check next candidate number of votes.
//loop
//winningtally = (candidate_count / 2);
//PROBLEM!!
winningtally = (voter_count / 2.0);
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes > winningtally)
{
//printf("Winner is: %s", candidates[i].name);
//printf("%s\n", candidates[i].name);
winrar = candidates[i].name;
winner = 1;
//return true;
//break;
}
else
{
i++;
}
}
if (winner == 0)
{
return false;
}
else
{
printf("%s\n", winrar);
return true;
}
}
// Return the minimum number of votes any remaining candidate has
int find_min(void)
{
// TODO
//find minimum number of votes
//
int min = 100;
for (int i = 0; i < candidate_count; i++)
{
if (min > candidates[i].votes && candidates[i].eliminated == false)
{
min = candidates[i].votes;
}
}
//return 0;
return min;
}
// Return true if the election is tied between all candidates, false otherwise
bool is_tie(int min)
{
int tiecounter = 0;
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes == min)
{
tiecounter++;
}
}
int candidatesleft = 0;
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].eliminated == false)
{
candidatesleft++;
}
}
//if (candidatesleft == candidate_count)
if (candidatesleft == tiecounter)
{
return true;
}
else
{
return false;
}
// TODO
}
// Eliminate the candidate (or candidates) in last place
void eliminate(int min)
{
// TODO
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes == min)
{
candidates[i].eliminated = true;
printf("Candidate %s has been eliminated\n", candidates[i].name);
}
}
return;
}