Cs50 plurality problem - Does not work in only 1 check - c

I made my code for the problem set 3 "plurality". When I check it, all answers are green, but there's only a problem with the "bob" answer
Here's the code, I include only the part with the function I implemented.
It's about a voting. In this function (after counting the votes for each candidate) you need to check who got the most votes and print the names. The function should take into consideration multiple winners. when I check the answer with the program given by cs50 all answers are red, only one answer marked as Bob but it doesn't explain what's the problem (in the previous problem set it did)
// Print the winner (or winners) of the election
void print_winner(void)
{
// Compare votes to select to biggest
for (int i = 0; i < (candidate_count -1); i++)
{
for (int j = 0; j < (candidate_count - 2); j++)
{
// swap bigger number and name to last index
if (candidates[i].votes > candidates[candidate_count - 1].votes)
{
candidates[candidate_count - 1].votes = candidates[i].votes;
candidates[candidate_count - 1].name = candidates[i].name;
}
}
}
// Print every candidates that have same votes as votes of last index
for (int i = 0; i < candidate_count; i++)
{
if (candidates[i].votes == candidates[candidate_count - 1].votes)
{
printf("%s\n", candidates[i].name);
}
}
return;
}
What's the problem?

Related

CS50 plurality - unable to print if there are too many winners

In plurality prblm, I managed to update votes for each candidate, my code can print the one winner, but still stuck if they are many winners .
help by hints or clues, not the whole solution.
Thanks in advance.
void print_winner(void)
{
int v = 0; //maximum number of votes
string w; //winner of the election
for (int i = 0; i < candidate_count; i++)
{
if (v <= candidates[i].votes)
{
v = candidates[i].votes;
}
}
for (int j = 0; j < candidate_count; j++)
{
if (candidates[j].votes == v)
{
w = candidates[j].name;
}
}
printf("%s\n", w);
return;
}
Change your second for loop to this:
for (int j = 0; j < candidate_count; j++)
{
if (candidates[j].votes == v)
{
w = candidates[j].name;
printf("%s\n", w);
}
}
You need to separate it into two for loops, if you have them together the first loop will run only through the first candidate with more than 1 vote and print it. Since it has not checked the others. That loops must finish and go through the whole set to actually find the max number of votes.
I am also on the same problem with you for around 2 or 3 days now. But I think I found out how to print if there are multiple winners.
First, I have a variable to store the highest votes and initialized it to 0. Then I tried comparing the candidates[i].votes against the current highest vote.
Then, I assigned the new value of the highest vote with the candidates vote until the loop finds someone who is higher than the previous one.
Lastly, I looped again through all the candidates and checks each candidates votes if they are equal to the highest vote. If yes, then their names should be printed. This solved my problem in printing 2 or more winners.

cs50 tideman (converting information from one array into another larger one)

I have completed and submitted the easier version of the problem set for the week I'm on, I'm just interested in finishing the harder version for the learning experience, but I'm stuck on what seems like the crux of it. Basically you are supposed to implement a voting system that records all the ranks of each of the voters. So for instance let's say you have 3 candidates (A, B, and C). If the first voter chooses candidate C as their first choice, and A as their second, (B as their last), the orginal array you would have looks like this [2,0,1] signifying that the the third candidate is the first choice, the first candidate is the second choice, and the second candidate is the third choice. The code I've used for this is the following:
bool vote(int rank, string name, int ranks[])
{
for (int i = 0; i < candidate_count; i++)
{
if(strcmp(candidates[i], name) == 0)
{
ranks[rank] = i;
for( int j = 0; j < candidate_count; j++)
{
printf("%i\n", ranks[j]);
}
return true;
}
}
return false;
}
But then we are asked to convert it into a 2d array that compares each of the candidates in basically a 1vs1 battle. So in our ABC example, the array should convert from [2,0,1] to [[0,1,0],[0,0,0],[1,1,0]]
where the first array represents the first candidate and how they did against the 2nd and 3rd respectively, etc. (the first location in the first array should always be 0 because you cant compare the candidate to how many votes they had against themself, same with the middle spot in the second array and the last spot in the last array). In other words array[i][j] represents how candidate i did against candidate j. You are meant to work this function out using the array returned from the vote function.
I know that it will involve another nested loop, possibly 3 layers. I need a point in the right direction. I've made a bunch of different tweaks to a function that looks like this but I know they've all been wrong because I'm resorting to trial and error rather than logic because the logic has defeated me at this point. Maybe this forum isn't really meant for logical help but I'd still like to work this out on my own without being given the answer. Anyway here's the latest version of the function that I've been helplessly tinkering with.
void record_preferences(int ranks[])
{
printf("\n");
for (int i = 0; i < candidate_count; i++)
{
for (int j = 0; j < candidate_count; j++)
{
for (int k = 0; k < candidate_count; k++)
{
if((ranks[k] > i && ranks[k] < j) || (ranks[k] < i && ranks[k] > j))
{
preferences[i][j] += 1;
}
}
printf("%i\n", preferences[i][j]);
}
}
return;
}
Keep in mind I've already gotten my grade for this week and I don't plan on submitting this work so it's not cheating even if you do straight up tell me the answer, but I'd prefer if you didn't. I know a lot of people are of the belief that you need to work the logic out yourself otherwise you're not really learning, which I kind of get, but at the same time you can only bang your head against a wall so many times before seeking help.
Thanks.
Edit: here is a link to a more clear explanation. The function in question starts around the 7:30 mark. https://www.youtube.com/watch?v=kb83NwyYI68&t=492s&ab_channel=CS50
Using the term vote instead of ranks for consistency with the video. It is also clearer as we also need to deal with the plural form votes.
The solution is a little long but the key insight is function rank() which returns the position of candidate for a given vote. We call the rank() for candidate i and j and incrementpreferences[i][j] if i ranks higher (<) than j.
Introduced enum candidates for readability (used candidate names from the video just to have a 2nd test case; comment out definition of QUESTION). This will also give you a compile error if you misspell a candidate name.
The code assumes that all candidates are ranked. It's straight forward to decouple number of candidates and the number of candidates that are being ranked.
#include <stdio.h>
#define LEN(a) (sizeof(a) / sizeof(*a))
enum candidates {
Alice,
Bob,
Charlie
};
void preferences_print(size_t candidates_len, unsigned preferences[candidates_len][candidates_len]) {
for(size_t i = 0; i < candidates_len; i++) {
for(size_t j = 0; j < candidates_len; j++) {
printf("%u%s", preferences[i][j], j + 1 < candidates_len ? ", " : "");
}
printf("\n");
}
}
unsigned rank(size_t candidates_len, unsigned vote[candidates_len], enum candidates candidate) {
for(size_t i = 0; i < candidates_len; i++) {
if(vote[i] == candidate) return i;
}
printf("Error: skipping invalid cadidate %d", candidate);
return 0;
}
void votes_to_preferences(size_t votes_len, size_t candidates_len, enum candidates votes[votes_len][candidates_len], unsigned preferences[candidates_len][candidates_len]) {
for(size_t v = 0; v < votes_len; v++) {
for(size_t i = 0; i < candidates_len; i++) {
for(size_t j = 0; j < candidates_len; j++) {
preferences[i][j] +=
rank(candidates_len, votes[v], i) <
rank(candidates_len, votes[v], j);
}
}
}
}
int main() {
enum candidates votes[][3] = {
#define QUESTION
#ifdef QUESTION
{ Charlie, Alice, Bob },
#else // VIDEO
{ Alice, Charlie, Bob },
{ Alice, Charlie, Bob },
{ Charlie, Alice, Bob },
{ Bob, Alice, Charlie }
#endif
};
unsigned preferences[LEN(*votes)][LEN(*votes)] = { { 0 } };
votes_to_preferences(LEN(votes), LEN(*votes), votes, preferences);
preferences_print(LEN(*votes), preferences);
return 0;
}

Implementing sorting algoritms on a struct [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am writing a program that calculates the winner of an election using the Tideman electorial system.
I have defined a struct called pair, in which two candidates are compared. The index of the candidate with the most votes is represented by winner and the candidate with the least votes by loser.
// Each pair has a winner, loser
typedef struct
{
int winner;
int loser;
}
pair;
these pairs are stored in a pairs array
pair pairs[MAX * (MAX - 1) / 2];
I am trying to sort this pairs array in decreasing order of strength of victory (defined as vote count for winner minus vote count for loser).
candidates are indexed into vote_count via their candidate index and the elements return their vote count. MAX pertains to the maximum number of candidates.
int vote_count[MAX]; // where i is the index of the candidate and the return value is the number of votes.
Here is my implementation of a selection sort:
int max_idx; // index of element with the highest strength of victory
// one by one move boundary of unsorterd subarray
for (int i = 0; i < array_size - 1; i++)
{
max_idx = i;
for (int j = i + 1; j < array_size; j++)
{
if (vote_count[pairs[j].winner] - vote_count[pairs[j].loser] > vote_count[pairs[i].winner] - vote_count[pairs[i].loser])
{
max_idx = j;
}
}
if (max_idx != i)
{
// swap the element with the highest strength of victory with the first element
swap(&pairs[max_idx], &pairs[i]);
}
}
return;
And here is my implementation of bubble sort:
for (int i = 0; i < array_size-1; i++)
{
for (int j = 0; j < array_size-i-1; j++)
{
if (vote_count[pairs[j].winner] - vote_count[pairs[j].loser] > vote_count[pairs[j+1].winner] - vote_count[pairs[j+1].loser])
{
swap(&pairs[j], &pairs[j+1]);
}
}
}
return;
Each call the swap function:
void swap(pair *xp, pair *yp)
{
pair temp = *xp;
*xp = *yp;
*yp = temp;
}
The vote_count array is filled during the call to another function, vote:
// Update ranks given a new vote
bool vote(int rank, string name, int ranks[])
{
// iterate through candidates
for (int i = 0; i < candidate_count; i++)
{
if (strcmp (name, candidates[i]) == 0) // if vote is for a valid candidate
{
// update rank array
ranks[rank] = i;
vote_count[i]++;
return true;
}
}
// if no candidate is found
return false;
}
Neither the selection sort or bubble sort is working for me, please let me know where i'm going wrong.
This does not exactly answer your question as asked, but you could create a comparator function and use qsort:
/* Vote count needs to be global or file static for this to work */
int vote_count[...];
...
int compare_pair(const void *p1, const void *p2)
{
int d1 = vote_count[((const pair *)p1)->winner] - vote_count[((const pair *)p1)->loser];
int d2 = vote_count[((const pair *)p2)->winner] - vote_count[((const pair *)p2)->loser];
return d2 - d1;
}
You could write this as a one-liner if you wanted, but it would be harder to read.
The sort then becomes
#include <stdlib.h>
...
qsort(pairs, MAX * (MAX - 1) / 2, sizeof(pair), compare_pair);

CS50 pset3: Plurality. Print_winner function incorrectly printing multiple candidates regardless of input when running the program

CS50's pset3 plurality requires you to print the winners of the "election" based on the number of votes they receive. Votes are input by the user.
My program's working fine up until I have to print the winners. I've been at it for a few days trying different methods but can't get my head around it.
My code currently outputs multiple candidates regardless of the input. I'm guessing that the variables "most_votes" and "election_winner" are retaining the assigned value from the top of the code.
How can I rewrite this to print a single winner if they receive the most votes and multiple winners if multiple candidates receive an equal number of votes?
Thanks for any help!
Here's my code:
// Print the winner (or winners) of the election
void print_winner(void)
{
int most_votes = candidates[0].votes;
string election_winner = candidates[0].name;
// Loop over each candidate
for (int i = 1; i < candidate_count; i++)
{
// Count how many votes each candidate received and determine who
// received the most votes
if (most_votes < candidates[i].votes)
{
most_votes = candidates[i].votes;
election_winner = candidates[i].name;
}
}
// Loop over candidates a second time
for (int j = 1; j < candidate_count; j++)
{
// Count how many votes each candidate received
// Compare number of votes of each candidate
// Check if mutiple candidates have the most votes
if (most_votes == candidates[j].votes && election_winner != candidates[j].name)
{
// Print all candidates with the most votes
printf("%s\n", candidates[j].name);
}
}
// Print the name of winner with most votes
printf("%s\n", election_winner);
return;
}
You do not need (and shouldn't have) the variable election_winner, if there can be multiple winners.
In the first loop only determine the value for most_votes.
Loop over the candidates a second time (starting from 0, not 1 as you are currently doing). If the vote count of the candidate equals most_votes, then you know that the candidate is a winner, and you may print the name out, or whatever else is required.
Thanks for the help guys I was able to figure it out. Simplified it as #vmt suggested and worked!
Changing the variable "most_votes" to "0" instead of "candidates[0].votes" made it easier to figure out.
// Print the winner (or winners) of the election
void print_winner(void)
{
int most_votes = 0;
// Loop over each candidate
for (int i = 0; i < candidate_count; i++)
{
// Count which candidate has the most votes and assign them most_votes
if (most_votes < candidates[i].votes)
{
most_votes = candidates[i].votes;
}
}
// Loop again over candidates
for (int j = 0; j < candidate_count; j++)
{
// Check if mutiple candidates have the most votes
if (most_votes == candidates[j].votes)
{
// Print all candidates with the most votes
printf("%s\n", candidates[j].name);
}
}
return;
}

How "struct" members are indexed? How to access them correctly in C?

How the "candidate" stuct is indexed in the following code?
When I try to print the last member(last index?) of the created struct which is candidates["last index"].name supposing I do have 4 candidates that will result the candidate_count which is = argc - 1 to equal to 4, so, I think if i accessed the 4th member by index of 4 I should reach the null terminator right? but that is not happening! the code looks like this
(Found at the end of the program)
printf("Winner is %s", candidates[4].name);
and It perfectly prints the 4th member name of the candidates name array! How is that?
Shouldn't it be like
printf("Winner is %s", candidates[3].name)
Here is the full program I wrote:
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
// Max number of candidates
#define MAX 9 // define MAX as a constant = 9 (or any number which might be used without '=' sign).
// define syntax won't allocate any memory for the constant 'MAX', it can be used later as int MAX
// which = int 9
// Candidates have name and vote count, stuct is the best to use to create a custom data type.
typedef struct
{
string name;
int votes;
}
candidate;
// Array of candidates
candidate candidates[MAX];
// Number of candidates as a global variable
int candidate_count;
// Function prototypes
bool vote(string name);
void print_winner(void);
int main(int argc, string argv[])
{
// Check for invalid usage, the args. must be more than 2, i.e 3 and up!
if (argc < 2)
{
printf("Usage: plurality [candidate ...]\n");
return 1;
}
// Populate array of candidates
candidate_count = argc - 1; // -1 because one argument is the program's name. the rest are the
// candidates' names.
if (candidate_count > MAX)
{
printf("Maximum number of candidates is %i\n", MAX);
return 2; // err code 2 means that the candidates number is exceeded
}
for (int i = 0; i < candidate_count; i++) // Store the candidates names from the argv[] into,
// the struct candidate of candidates.name[] array to be globally available.
{
candidates[i].name = argv[i + 1]; // +1 because the 0th index is the programs name.
candidates[i].votes = 0; // initializing 0 for all candidates
}
// Enter the number of people allowed to vote, in other words, total number of votes allowed.
int voter_count = get_int("Number of voters: ");
// Loop over all voters to enter their votes for a candidate of the available names.
for (int i = 0; i < voter_count; i++)
{
string name = get_string("Vote: ");
// Check for invalid vote
if (!vote(name)) // Use function vote(string name) to check for the presence,
//of the candidate's name.
{
printf("Invalid vote.\n");
}
}
// Display winner of election
print_winner(); // call this func. to print the winner's name.
}
// Update vote totals given a new vote
bool vote(string name)
{ // loop over all candidates names checking it's availability by comparing it to user-entered name.
// global variable candidate_count is used to keep track of number of candidates.
for (int i = 0; i < candidate_count ; i++)
{
if (strcmp (name, candidates[i].name) == 0)
{
// Update the candidate's vote count.
candidates[i].votes++; // update the votes count for the candidate indexed # i.
return true;
}
} // End for() iteration over the candidates names indeces.
return false;
}
// Print the winner (or winners) of the election
void print_winner(void)
/*
Bubble sorting Algorithm;
- A pass is a number of steps where the adjacent elements are compared to eachother from left to right in
an int array each one with the one next to it.
- If an array has a number of elements of 5, so, n = 5.
- There will always be a maximum of n - 1 passes in bubble sorting
- There will be a maximum of n - 1 comparisons of items in each pass if code is not optimized
*/
{
int swap = 0; // A flag to check if swapping happened.
//( To check if the array is sorted, swap happening = not sorted yet else the array is sorted)
for (int i = 0; i <= candidate_count - 1; i++) // passes = n - 1 where n = number of elements to compare.
{
for (int j = 0; j <= candidate_count - 1 - i; j++) // Number of comparisions(elements to be checked -
// with thier adjacent ones) to be conducted in each pass, after pass the last element will always
// be the greatest element there for no need to compare it with the element before it. therefore,
// candidate_count - 1 - i where i value starting form 0 by the outer for loop reduces the number -
// of steps or elements to be checked each iteration
{
/* if the first candidate number of votes element in the array is Greater-Than the adjacent next
one, swap them and keep a flag or indicate that you did swap them.
*/
if ( candidates[j].votes > candidates[j + 1].votes)
{
// Swap the position of the struct candidates elements inside
candidate temp = candidates[j];
candidates[j] = candidates[j + 1];
candidates[j + 1] = temp;
swap = 1; // a flag to indicated the swapping actually happened.
} // End swapping if() statement.
}
if (swap == 0) // if no swapping happened
break;
}
/* When Populating array of candidates, candidate_count = argc - 1; // -1 because one argument
is the program's name. the rest are the candidates' names.
*/
printf("Winner is %s, candidate count = %d \n", candidates[candidate_count].name, candidate_count);
return;
}
Copied from comments:
if I run the program in terminal and adding "printf"s to print candidates names & votes starting from index 0 to 5, that is what i am getting:
c ~/pset3/plurality/ $ ./plurality moh zoz sos
Number of voters: 5
Vote: moh
Vote: moh
Vote: moh
Vote: zoz
Vote: sos
Winner is moh, candidate count = 3
The candidate name : (null) votes : 0
The candidate name : zoz votes : 1
The candidate name : sos votes : 1
The candidate name : moh votes : 3
The candidate name : (null) votes : 0
The candidate name : (null) votes : 0
SOLUTION is just removing the 'equal to' from this line's condition:
for (int j = 0; j <= candidate_count - 1 - i; j++)
to look like this
for (int j = 0; j < candidate_count - 1 - i; j++)
Your bubble-sort has an error.
The condition for the second loop is j <= candidate_count - 1 - i but it should be j <= candidate_count - 2 - i. This is because you swap the elements at j and j+1. But with your condition j == candidate_count - 1 which results in a swap of candidate_count-1 and candidate_count.
To find such mistakes you should either learn how to use a debugger or add debug output to your program like
printf("swap(%d, %d)\n", j, j+1);
then you can better understand what your program actual does.
As a sidenote:
The sorting of candidates is not necessary as you can simply iterate through the array and search the candidate with the biggest vote, like:
if (candidate_count < 1) {
// some error handling
} else {
candidate biggest = candidates[0];
for (int i = 1; i < candidate_count; i++) {
if (biggest.vote < candidates[i].vote) {
biggest = candidates[i];
}
}
// do what ever you want to do with the winner
}

Resources