Skip to content

Instantly share code, notes, and snippets.

@AnimeshRy
Last active June 26, 2024 19:39
Show Gist options
  • Save AnimeshRy/489d3c19db9d179c7c562bad24c4b3ee to your computer and use it in GitHub Desktop.
Save AnimeshRy/489d3c19db9d179c7c562bad24c4b3ee to your computer and use it in GitHub Desktop.
CS50 Runoff Pset3
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <stdbool.h>
#include <math.h>
// Max voters and candidates
#define MAX_VOTERS 100
#define MAX_CANDIDATES 9
// preferences[i][j] is jth preference for voter i(2d array)
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
//passed i,j and name of the candidate the user entered, look at line 77
bool vote(int voter, int rank, string name)
{
bool exist = false;
for (int i = 0; i < candidate_count; i++)
{
//check if name is present in the candidates entered by the user by camparing two strings
//strcmp is checking for the name and camparing it to the candidates array location 'i' which starts according to the for loop above
if (strcmp(name, candidates[i].name) == 0)
{
//if you found the person is present then add that number as a rank of the candidate in the preferences array
//suppose this is a 2d array and the preference array is adding the preference number on a specific poistion so
// here ex - preferences[0][0] = i (the rank preferences from the candidate count)
// [i][][][]
// [][][][]
// [][][][]
// [][][][]
preferences[voter][rank] = i;
exist = true;
break;
//This is a bool conditions which will become true, again look at line 77
}
}
return exist;
}
// Tabulate votes for non-eliminated candidates
void tabulate(void)
{
// TODO
for (int i = 0; i < voter_count; i++)
{
for (int j = 0; j < candidate_count; j++)
{
if (candidates[preferences[i][j]].eliminated == false)
{
candidates[preferences[i][j]].votes += 1;
break;
}
}
}
return;
}
// Print the winner of the election, if there is one
bool print_winner(void)
{
// TODO
for (int i = 0; i < candidate_count; i++)
{
string most = candidates[i].name;
if (candidates[i].votes > voter_count / 2)
{
printf("%s\n", most);
return true;
}
}
return false;
}
// Return the minimum number of votes any remaining candidate has
int find_min(void)
{
int minvotes = voter_count;
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].eliminated == false && candidates[i].votes < minvotes)
{
minvotes = candidates[i].votes;
}
}
return minvotes;
}
// Return true if the election is tied between all candidates, false otherwise
bool is_tie(int minvotes)
{
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].eliminated == false && candidates[i].votes != minvotes)
{
return false;
}
}
return true;
}
// Eliminate the candidate (or candidiates) in last place
void eliminate(int minvotes)
{
for (int i = 0; i < candidate_count; i++)
if (candidates[i].votes == minvotes)
{
candidates[i].eliminated = true;
}
return;
}
@TheoMariott1
Copy link

TheoMariott1 commented Aug 29, 2020

Hello @AnimeshRy

On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?

Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.

Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.

When I run check50 it gives me these red warnings:

:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true

Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

@AnimeshRy
Copy link
Author

Hello @AnimeshRy
On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?
Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.

Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.

When I run check50 it gives me these red warnings:

:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true

Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

You don't need the round function when you are already storing the values in a int. Also you are casting the round function wrong here.

round(var)

is the correct way. But none of them is the problem in your code, the most likely problem is not using the"\n" in your print statement. Check50 checks the output from top to bottom line by line so a wrong newline is a problem. I haven't tried your function for check50 but newline being a problem is highly probable.

@NazokatkhonM
Copy link

Hello @AnimeshRy
On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?
Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.

Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.

When I run check50 it gives me these red warnings:

:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true

Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

@TheoMarriot1
Thank you so much for explaining that concept to me. Good luck in your coding journey!

@TheoMariott1
Copy link

TheoMariott1 commented Aug 30, 2020

Hello @AnimeshRy
On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?
Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.
Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.
When I run check50 it gives me these red warnings:
:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true
Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

You don't need the round function when you are already storing the values in a int. Also you are casting the round function wrong here.

round(var)

is the correct way. But none of them is the problem in your code, the most likely problem is not using the"\n" in your print statement. Check50 checks the output from top to bottom line by line so a wrong newline is a problem. I haven't tried your function for check50 but newline being a problem is highly probable.

Hi! Thanks for pointing it out, I later actually noticed that and removed from my actual code (it was a leftover of some float conversion strategy I tried earlier that also didn't work), but as you said it wasn't the root of the problem...

I will try placing a newline in print to see if it works then

@TheoMariott1
Copy link

Hello @AnimeshRy
On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?
Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.
Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.
When I run check50 it gives me these red warnings:
:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true
Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

@TheoMarriot1
Thank you so much for explaining that concept to me. Good luck in your coding journey!

Glad I could help! Good luck to you as well (:

@TheoMariott1
Copy link

Hello @AnimeshRy
On line 204 of your code, it says "return minvotes". I understand that it doesn't work otherwise so I would like to inquire about the following questions:
What is the logic behind that statement?
Why can't it "return true" or anything else?
Thanks in advance for your help!

Hi, I think I might be able to answer your question. In the return logic of a boolean function you need in fact to return true or false value. But that is a function made to return an integer instead, so the return value of the function must be of the same type it was declared in the first place. Consider the function declaration: int find_min(void)
This statement defines the return value that function must provide. Which in this case is the integer value stored in minvotes, that will later be used by other functions to know the fewest number of votes one or more of the candidates have.
Additionally I would like to ask about a doubt myself to @AnimeshRy or any person willing.
When I run check50 it gives me these red warnings:
:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true
Below is my print_winner() function which is very similar to the one presented by AnimeshRy and yet it does not seem to be correct. I went through debugging every step and even compared some other functions to see if I was missing something. But the thing is that it seems to check out... I'm cracking my head on this. Here's the function:

bool print_winner(void)
{
    int half = (round)(voter_count / 2);
    for (int i = 0; i < candidate_count; i++)
    {
        if (candidates[i].votes > half)
        {
            printf("%s", candidates[i].name);
            return true;
        }
    }
    return false;
}

Every other checkpoint is met in the test. Any ideas what could be giving this?

You don't need the round function when you are already storing the values in a int. Also you are casting the round function wrong here.

round(var)

is the correct way. But none of them is the problem in your code, the most likely problem is not using the"\n" in your print statement. Check50 checks the output from top to bottom line by line so a wrong newline is a problem. I haven't tried your function for check50 but newline being a problem is highly probable.

Hi! Thanks for pointing it out, I later actually noticed that and removed from my actual code (it was a leftover of some float conversion strategy I tried earlier that also didn't work), but as you said it wasn't the root of the problem...

I will try placing a newline in print to see if it works then

It was, in fact, the new line... This got me hooked for almost a week, ngl feels kinda embarrasing... 😅

@AnimeshRy I don't know what I would do without you. Really appreciate the help! 🥇

@ganeshsinghal2005
Copy link

Hey... I am a new junior in cs50.. So please can u make me understand the meaning of line 54 from where the for loop starts. What is that for loop representing??

@ganeshsinghal2005
Copy link

I will be really obliged for your answer...

@tara8970
Copy link

candidates[preferences[i][j]].votes
Can someone explain how these two things got combined? I thought preferences array was separate, and not totally understanding how we can just put it into the candidate struct variable. I am very new to any kind of programming, and wasn't sure what to even google to find this answer.

Also, if anyone has a good site they can recommend for some of the basic functions/rules of C.

@NazokatkhonM
Copy link

NazokatkhonM commented Sep 18, 2020

candidates[preferences[i][j]].votes
Can someone explain how these two things got combined? I thought preferences array was separate, and not totally understanding how we can just put it into the candidate struct variable. I am very new to any kind of programming, and wasn't sure what to even google to find this answer.

Also, if anyone has a good site they can recommend for some of the basic functions/rules of C.

I remember being very confused as well with programming, but it will definitely get better :).
Now, for your question. With candidates[preferences[i][j]].votes, you are indicating the number of votes the candidates has, in each voters preference.
Let me implement this more graphically!
So, when implementing the below function:

void tabulate(void)
{
// TODO
for (int i = 0; i < voter_count; i++)
{
for (int j = 0; j < candidate_count; j++)
{
if (candidates[preferences[i][j]].eliminated == false) \ if your candidate's elimination status in voters [i][j] is FALSE, thus not eliminated, do the below
{
candidates[preferences[i][j]].votes += 1; \ this just increments the above candidates votes by 1.
break;
}
}

}
return;

}

Now, candidates[preference[i][j]].votes indicates the amount of votes each candidate has in each voters preference array.
I hope I explained that clearly, but if you have any questions, please, please, please DO NOT hesitate to add another reply. @tara8970

@tara8970
Copy link

Thanks very much!

@NourSabry
Copy link

can anyone tell me what this message mean ?

linker command failed with exit code 1 (use -v to see invocation)
: recipe for target 'runoff' failed
make: *** [runoff] Error 1

@AnimeshRy
Copy link
Author

can anyone tell me what this message mean ?

linker command failed with exit code 1 (use -v to see invocation)
: recipe for target 'runoff' failed
make: *** [runoff] Error 1

Maybe you are not using the make statement right. Select the right directory and use make runoff to make it work. Make files is like a automation tool where the compilation and execution is done together rather than using clang -o file file.o. If these steps don't work, make a new file in a new dir and try again.

@tara8970
Copy link

tara8970 commented Oct 16, 2020 via email

@NourSabry
Copy link

can anyone tell me what this message mean ?
linker command failed with exit code 1 (use -v to see invocation)
: recipe for target 'runoff' failed
make: *** [runoff] Error 1

Maybe you are not using the make statement right. Select the right directory and use make runoff to make it work. Make files is like a automation tool where the compilation and execution is done together rather than using clang -o file file.o. If these steps don't work, make a new file in a new dir and try again.

i'll try again ty so much

@NourSabry
Copy link

Make sure you made your runoff.c in runoff and not just out in pset2 or whatever it is. It should be indented under runoff, not in line with the pset number. Best regards Tara Green-Webber Administrative Manager - Xconditioning [email protected] 250.617.9838

On Oct 16, 2020, at 9:24 AM, Animesh @.***> wrote: @AnimeshRy commented on this gist. can anyone tell me what this message mean ? linker command failed with exit code 1 (use -v to see invocation) : recipe for target 'runoff' failed make: *** [runoff] Error 1 Maybe you are not using the make statement right. Select the right directory and use make runoff to make it work. Make files is like a automation tool where the compilation and execution is done together rather than using clang -o file file.o. If these steps don't work, make a new file in a new dir and try again. — You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or unsubscribe.

will make sure of it thank you really !

@Nnanyere
Copy link

In line 165 and 167, why do you use candidates[preferences[i][j]].eliminated instead of candidates[i].eliminated?

See above, we used two loops and are iterating over all voters who gave votes to all the candidates and where did we save the votes on these voters? preferences[i][j]

Shouldn't we only be updating preferences[i][0].votes since second-place votes shouldn't be counted the first time around?

@ys-cao
Copy link

ys-cao commented Nov 25, 2020

I had applied the similar logic for find_min() function but it shows error in check 50 command. Isn't your code showing the error

:( find_min returns minimum when all candidates are tied
find_min did not identify correct minimum
:( find_min ignores eliminated candidates
find_min did not identify correct minimum

Because you didn't set candidates[i].eliminated == true.

In this case, it will return true if you have already eliminated some candidates.

try this
bool is_tie(int min) { for (int c = 0; c < candidate_count; c++) { if (candidates[c].eliminated == false && candidates[c].votes != min) { return false; } else if (candidates[c].eliminated == true) { return false; } } return true; }

@targerian
Copy link

candidates[preferences[i][j]].votes
Can someone explain how these two things got combined? I thought preferences array was separate, and not totally understanding how we can just put it into the candidate struct variable. I am very new to any kind of programming, and wasn't sure what to even google to find this answer.
Also, if anyone has a good site they can recommend for some of the basic functions/rules of C.

I remember being very confused as well with programming, but it will definitely get better :).
Now, for your question. With candidates[preferences[i][j]].votes, you are indicating the number of votes the candidates has, in each voters preference.
Let me implement this more graphically!
So, when implementing the below function:

void tabulate(void)
{
// TODO
for (int i = 0; i < voter_count; i++)
{
for (int j = 0; j < candidate_count; j++)
{
if (candidates[preferences[i][j]].eliminated == false) \ if your candidate's elimination status in voters [i][j] is FALSE, thus not eliminated, do the below
{
candidates[preferences[i][j]].votes += 1; \ this just increments the above candidates votes by 1.
break;
}
}

}
return;

}

Now, candidates[preference[i][j]].votes indicates the amount of votes each candidate has in each voters preference array.
I hope I explained that clearly, but if you have any questions, please, please, please DO NOT hesitate to add another reply. @tara8970

Won't that make you add votes for all the [voters,candidates] array not only [voters,0] in the first iteration?

@rohanasif
Copy link

i'm getting this when making runoff

runoff.c:78:20: error: implicit declaration of function 'print_winnner' is invalid in C99 [-Werror,-Wimplicit-function-declaration]
bool won = print_winnner();

@Ahmed8-dev
Copy link

why you include #include <stdbool.h> & #include <math.h>????

@wx5162839
Copy link

wx5162839 commented Feb 21, 2022 via email

@Manish-mech
Copy link

I really appreciate your work man, you are helping students to solve mind-boggling problem sets. And your explanation is very easy to understand.
but, there is only one thing I am facing a problem with, I took references from many other answers as well but the same issues I am having. I am unable to visualize the pseudo code for the is_tie function, I mean, I can't able to visualize what it is doing. Can you elaborate on the pseudo-code for it?
When it will give true or when false.
It will be very helpful.

@wx5162839
Copy link

wx5162839 commented Apr 28, 2022 via email

@danilkkv
Copy link

danilkkv commented Sep 9, 2022

thanks for your work on this mind-boggling problem! Can someone explain why is_tie works though? I really could not understand your reasoning behind this function :/

@wx5162839
Copy link

wx5162839 commented Sep 9, 2022 via email

@Blue-Dragon1777
Copy link

Check CS50 is giving me this response:
:( print_winner prints name when someone has a majority
print_winner did not print winner of election
:( print_winner returns true when someone has a majority
print_winner did not print winner and then return true
:( print_winner returns false when nobody has a majority
print_winner did not return false
:( print_winner returns false when leader has exactly 50% of vote
print_winner did not return false

and this is my print_winner function:

bool print_winner(void)
{
for ( int i = 0; i < candidate_count; i++ )
{
if (candidates[i].votes > (candidate_count / 2))
{
printf("%s\n", candidates[i].name);
return true;
}
}

return false;

}

I am not able to understand where the problem is, if anybody can point it out for me it'll be a huge help.
Thanks in advance for your help

@wx5162839
Copy link

wx5162839 commented Dec 1, 2022 via email

@medha30saxena
Copy link

please help me because as I run this code it is not compiling properly instead after entering one rank is giving the output of invalid .

@wx5162839
Copy link

wx5162839 commented Dec 29, 2022 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment