The code I write has to run a runoff election. I have finished all of the code already that I have to do. However, I get an issue in the tabulate function. I passed all the checks when I ran it through check50 for all my code except a specific error in the tabulate function.
Some questions I got asked for a reproducible example. I found an example someone used for code and it produces the error in my code as well. I inputted 4 candidates (a,b,c,d) and 5 voters with their preferences ranked. The winner of this election should be candidate b. However, my code outputs candidates a, b, and d as the winners.
Voter 1: d,c,b,a
Voter 2: a,b,c,d
Voter 3: a,b,c,d
Voter 4: b,c,a,d
Voter 5: b,c,a,d
The specific error I am getting is -
:( tabulate handles multiple rounds of preferences tabulate did not produce correct vote totals
I've looked through multiple solutions people have had on here but couldn't find anything related to the code I wrote.
This is my code
#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;
// 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);
int main(int argc, string argv[])
{
    // Check for invalid usage
    if (argc < 2)
    {
        printf("Usage: runoff [candidate ...]\n");
        return 1;
    }
    // Populate array of candidates
    candidate_count = argc - 1;
    if (candidate_count > MAX_CANDIDATES)
    {
        printf("Maximum number of candidates is %i\n", MAX_CANDIDATES);
        return 2;
    }
    for (int i = 0; i < candidate_count; i++)
    {
        candidates[i].name = argv[i + 1];
        candidates[i].votes = 0;
        candidates[i].eliminated = false;
    }
    voter_count = get_int("Number of voters: ");
    if (voter_count > MAX_VOTERS)
    {
        printf("Maximum number of voters is %i\n", MAX_VOTERS);
        return 3;
    }
    // Keep querying for votes
    for (int i = 0; i < voter_count; i++)
    {
        // Query for each rank
        for (int j = 0; j < candidate_count; j++)
        {
            string name = get_string("Rank %i: ", j + 1);
            // Record vote, unless it's invalid
            if (!vote(i, j, name))
            {
                printf("Invalid vote.\n");
                return 4;
            }
        }
        printf("\n");
    }
    // Keep holding runoffs until winner exists
    while (true)
    {
        // Calculate votes given remaining candidates
        tabulate();
        // Check if election has been won
        bool won = print_winner();
        if (won)
        {
            break;
        }
        // Eliminate last-place candidates
        int min = find_min();
        bool tie = is_tie(min);
        // If tie, everyone wins
        if (tie)
        {
            for (int i = 0; i < candidate_count; i++)
            {
                if (!candidates[i].eliminated)
                {
                    printf("%s\n", candidates[i].name);
                }
            }
            break;
        }
        // Eliminate anyone with minimum number of votes
        eliminate(min);
        // Reset vote counts back to zero
        for (int i = 0; i < candidate_count; i++)
        {
            candidates[i].votes = 0;
        }
    }
    return 0;
}
// Record preference if vote is valid
bool vote(int voter, int rank, string name)
{
    // TODO
    //loop over all candidates, and within each voter saves their preferences for each candidate
    for (int i = 0; i < candidate_count; i++)
    {
        if (strcmp(candidates[i].name, name) == 0)
        {
            preferences[voter][rank] = i;
            return true;
        }
    }
    return false;
}
// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
    // TODO
    //loop over all voters
    for (int i = 0; i < voter_count; i++)
    {
        //check voter(i's) 1st preference(0th index), if voter(i) 1st preference isn't eliminated, update vote for candidate 1(0th index)
        //if voter(i) 1st preference is eliminated, check voter(i) 2nd preference
        //if 2nd preference isn't eliminated, update vote for candidate corresponding to 2nd candidate, voter[i][j+1]
        for (int j = 0; j < candidate_count; j++)
        {
            if (candidates[preferences[i][j]].eliminated == false)
            {
                candidates[preferences[i][j]].votes++;
            }
            else if(candidates[preferences[i][j]].eliminated == true)
            {
                candidates[preferences[i][j+1]].votes++;
            }
            break;
        }
    }
    return;
}
// Print the winner of the election, if there is one
bool print_winner(void)
{
    // TODO
    //define variable highest_vote to zero
    int majority_vote = voter_count/2;
    //loop over every candidate, if their vote count is higher than highest_vote, set highest_vote equal to the highest candidates vote count
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > majority_vote)
        {
            printf("%s\n", candidates[i].name);
            return true;
        }
    }
    return false;
}
// Return the minimum number of votes any remaining candidate has
int find_min(void)
{
    // TODO
    int min_votes = voter_count;
    //loop through all candidates to find lowest vote count
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].eliminated == false && candidates[i].votes < min_votes)
        {
            min_votes = candidates[i].votes;
        }
    }
    return min_votes;
}
// Return true if the election is tied between all candidates, false otherwise
bool is_tie(int min)
{
    // TODO
    bool tie_check = false;
    //loop through all candidates, if candidates are tied, variable will be true
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].eliminated == false && candidates[i].votes == min)
        {
            tie_check = true;
        }
        else if (candidates[i].eliminated == false && candidates[i].votes != min)
        {
            tie_check = false;
        }
    }
    if (tie_check == true)
    {
        return true;
    }
    else
    {
        return false;
    }
}
// Eliminate the candidate (or candidates) in last place
void eliminate(int min)
{
    // TODO
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].eliminated == false && min == candidates[i].votes)
        {
            candidates[i].eliminated = true;
        }
    }
    return;
}
