简体   繁体   中英

CS50, Pset3 Runoff, everything works excepts tabulate function

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;
}

I just found out what was wrong with my code. It lied in

            else if (candidates[preferences[i][j]].eliminated == true)
            {
                candidates[preferences[i][j + 1]].votes++;
            }
            break;

This was causing my code to incorrectly update the vote count for the candidates. My thought process for writing this code was if the candidate for that rank was eliminated, then add a vote to the next preference or rank which was the candidates[preferences[i][j+1]].votes++; line. This caused a misalignment in my votes count so here is my solution. It was also unnecessary because I could have just added a break; into the if statement.

I deleted the entire code that was wrong above. Then I simply added a break; into the if statement. The correct tabulate function now looks like this as a completed version.

// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
    //loop over all voters
    for (int i = 0; i < voter_count; i++)
    {
        //loop over all candidates
        //check voter(i's) 1st preference(0th index), if voter(i) 1st preference isn't eliminated, update vote for candidate 1(0th index)
        //break out of the loop so you don't update votes for all preferences for each voter
        for (int j = 0; j < candidate_count; j++)
        {
            if (candidates[preferences[i][j]].eliminated == false)
            {
                candidates[preferences[i][j]].votes++;
                break;
            }
        }
    }
    return;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM