0

I am having difficulty seeing where I am going wrong here with my tabulate and find-min functions. I have been checking the other functions, which execute properly, as I go along. Any direction or suggestions would be greatly appreciated here! Thank you in advance! My code is below.

#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)
{
    // Create a variable to store who is voting and count - already preference to store - iterate over each candidate
    for (int i = 0; i < candidate_count; i++)
    {
        //Compare name on the vote to candidates name
        if (strcmp(candidates[i].name, name) == 0)
        {
            //Index into preferences in candidates array and store
            preferences[voter][rank]=i;
            return true;
        }
    }

    return false;
}

// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
    for (int i=0; i < voter_count; i++)
    {
        for (int j=0;j < candidate_count; j++)
        {
            if (!candidates[i].eliminated == 0)
            {
                //Add votes
                candidates[i][j].votes++;
                break;
            }
        }
        return;
    }
}

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

// Return the minimum number of votes any remaining candidate has
int find_min(void)
{
    int min = candidate_count;

    for (int i=0; i<candidate_count;i++)
    {
        if (candidates[i].votes < min)
            if (!candidates[i].eliminated)
            {
                min = candidates[i].votes;
            }
    }
    return min;
}

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

// Eliminate the candidate (or candidates) in last place
void eliminate(int min)
{
    for (int i=0; i <candidate_count; i++)
    {
        if (candidates[i].votes == min && !candidates[i].eliminated)
        {
            candidates[i].eliminated = true;
        }
    }
    return;
}

1 Answer 1

0
  • this line is of poor quality and more confusing than needed: if(!candidates[i].eliminated==0).
    you set eliminated to false initially, and later potentially set it to true. make your code clearer and just ask for the condition you want.... which seems to be candidates[i].eliminated == false

  • you have a return in the wrong place in your tabulate function which is clear when you fix the indentation. That is surely mucking up everything.

  • you could simplify your find_min function by combining the two if's together

if (candidates[i].votes < min)
    if (!candidates[i].eliminated)

can be intelligently shortened to just
if ( candidates[i].eliminated == false && candidates[i].votes < min )

  • be consistent... sometimes you say !candidates[i].eliminated sometimes you say candidates[i].eliminated == false Strongly suggest you solely use the more verbose version at this level of programming... If not then only use candidates[i].eliminated and not-ing it. Be consistent.

  • run style50 before posting your code anywhere in the future please.

  • tabulate shouldn't even compile this line of code is quite wrong should be a syntax error: candidates[i][j].votes++; it's incorrect, candidates is a single dimensional array. The problem is you are looking in entirely the wrong place. You need to be looking in preferences which you assign in vote but never refer to anywhere else. Pretty sure you want something like this:

// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
    // for each voter
    for (int voter_id = 0; voter_id < voter_count; voter_id++)
    {
        // for each preference in order of preference that voter has
        for (int rank = 0; rank < candidate_count; rank++)
        {
            int candidate_id = preferences[voter_id][rank];
            // if this level preference exists vote for them else continue to next preference.
            if ( candidates[candidate_id].eliminated == false)
            {
                //Add vote
                candidates[candidate_id].votes++;
                break; // move on to next voter
            }
        }
    }
}
  • I would strongly encourage you to use variable names that are actually meaningful to what you are doing. I demonstrated this for you in the above code where my comments are practically unneeded because of how clear the variable names are.
1
  • Thank you for your clarifications and suggestions. Definitely helpful for someone new to this.
    – Jeff
    Commented Dec 12, 2023 at 2:22

You must log in to answer this question.

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