2

i have completed the problem set however when i check, this is the only problem.

:) tabulate counts votes when all candidates remain in election :) tabulate counts votes when one candidate is eliminated :( tabulate counts votes when multiple candidates are eliminated tabulate function did not produce correct vote totals

i have checked and cant seem to find the solution even through debugging?also i feel like the function is logical and does not contain issues i found in other related questions.

i have included all the code in case the issue does not lie with the tabulate function. thank you.

#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)
{
    for(int x = 0; x < candidate_count; x++)
    {
        if (strcmp(name,candidates[x].name) == 0)
        {
            preferences[voter][rank] = x;
            return true;
        }
    }
    return false;
}
// Tabulate votes for non-eliminated candidates        **here is the relevant code**
void tabulate(void)
{
    for (int v = 0; v < voter_count; v++)
    {
        for (int r = 0; r < candidate_count; v++)
        {
            if(candidates[preferences[v][r]].eliminated == false )
            {
                candidates[preferences[v][r]].votes++;
                break;
            }
        }
    }
    return;
}

// Print the winner of the election, if there is one
bool print_winner(void)
{
    for(int c = 0; c < candidate_count; c++)
    {
        if (candidates[c].votes > (voter_count * 0.5))
        {
            printf("%s\n",candidates[c].name);
            return true;
        }
    }
    return false;
}

// Return the minimum number of votes any remaining candidate has
int find_min(void)
{
    int min[1] = {0};
    for ( int c = 0; c < candidate_count; c++)
    {
        if (candidates[c].votes > min[0])
        {
            min[0] = candidates[c].votes;
        }
    }
    return min[0];
}

// Return true if the election is tied between all candidates, false otherwise
bool is_tie(int min)
{
    for (int c = 0; c< candidate_count; c++)
    {
        if (candidates[c].votes != min && candidates[c].eliminated == false)
        {
            return false;
        }
    }
    return true;
}

// Eliminate the candidate (or candidiates) in last place
void eliminate(int min)
{
    for (int c = 0; c < candidate_count; c++)
    {
        if (candidates[c].votes == min)
        {
            candidates[c].eliminated = true;
        }
    }
    return;
}
2
  • The debugger will help if there is data that fails the test. Try this election: 4 candidates: a,b,c,d. 4 Voters , voter1: a,d,b,c, voter2: a,d,b,c voter3: d,a,b,c voter4: d,a,b,c Commented Feb 14, 2020 at 12:39
  • I actually have a question about your code, can you explain why in the find_min function you use an array called min and establish min[0] as the value holder for the lowest number of votes? I'm not sure how that works. Commented Apr 26, 2020 at 22:59

4 Answers 4

1

I think there a problem with this line of code:

        if(candidates[preferences[v][r]].eliminated == false )
        {
            candidates[preferences[v][r]].votes++;
            break;

What happens when it finds the first choice for a candidate has been eliminated? Because it needs to check what his next choice is and so forth. Until it ether finds a candidate that has not been eliminated or there is no more candidates.

5
  • thanks my intention was that if the first choice was eliminated, then r++ so the next rank would be checked. so the logic works out. however the issue was just a stupid mistake typo v for r. for (int r = 0; r < candidate_count; v++) cant believe i just saw that.
    – yui
    Commented Feb 17, 2020 at 17:37
  • @yui I know this is an old post but would be awesome if you can help. For the tabulate function, I was doing check50 on this same code but without the line "break;" it didn't work. Yet with the line "break;" it does work. My question is, what does this "break;" line actually do here?
    – Dimi3
    Commented Sep 13, 2020 at 15:51
  • the line "break;" stops the second loop once a vote has been added as only the highest preference of the voter should be counted unless the highest preference is eliminated in which case the the highest preference that has not been eliminated should be counted Commented Dec 7, 2020 at 21:18
  • Consider checking My answer for the problem he is facing in the code above cs50.stackexchange.com/a/41845/34124 Commented Aug 28, 2021 at 14:28
  • 1
    @yui i had the same problem and nearly the same typo... your comment made me check and find it :)
    – Philip F
    Commented May 17, 2022 at 10:46
1

How does this function returns the minimum votes and not the maximum votes?

int find_min(void)
{
    int min[1] = {0};
    for ( int c = 0; c < candidate_count; c++)
    {
        if (candidates[c].votes > min[0])
        {
            min[0] = candidates[c].votes;
        }
    }
    return min[0];
}
1

I was Encountering the same error and that was all due to a silly mistake we both have done. Have a Look here in the code

void tabulate(void)
{
    for (int v = 0; v < voter_count; v++)
    {
        for (int r = 0; r < candidate_count; v++)
        {
            if(candidates[preferences[v][r]].eliminated == false )
            {
                candidates[preferences[v][r]].votes++;
                break;
            }
        }
    }
    return;
}

Now have a closer look at this line only

for (int r = 0; r < candidate_count; v++)

You are Initialising r = 0;. But Incrementing v++; Just Replace that Vwith r and you are done.

1
  • Oh my god, when I looked at the topic starter's function I immediately saw this mistake. And then I realized I had made the same stupid mistake myself either ._. Commented Sep 9, 2023 at 10:39
0

I can find nothing wrong with your logic, and I did the exact same thing, have a look if this solves the problem. I just used different syntax and it works: (before we got into the loop, I initialized temp) int temp; . . . temp = preferences[v][r];

if (!candidates[temp].eliminated) { candidates[temp].votes++; break; }

I'm not sold on why this should work vis-a-vis what you did, but sometimes syntax does make a difference - and for some reason this works for me

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .