Advertisement
bocajbee

tideman.c

Feb 28th, 2020
2,253
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 12.49 KB | None | 0 0
  1. #include <cs50.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4.  
  5. #define MAX 9  // max number of candidates that can be in the election. 9
  6.  
  7. int preferences[MAX][MAX];  // preferences[i][j] is a 2d array to represent the number of voters who prefer candiate[i] over candidate[j], using an adjacency matrix
  8.  
  9. bool locked[MAX][MAX];  // 2d boolean array, used to keep track of the candidate graph. if locked[i][j] == TRUE, we've locked in the edge pointing from candidate "i" to candidate "j"
  10.  
  11. typedef struct  // a struct used to declare each pair, which has a winner & loser
  12. {
  13.     int winner;
  14.     int loser;
  15. }
  16. pair;
  17.  
  18. string candidates[MAX];  // array of strings, for the candidates names, candidate[0] is the 1st candidate. candidate[1] is the 2nd candidate etc...
  19. pair pairs[MAX * (MAX - 1) / 2];  // array of the MAX amount of candidates * (MAX amount of candidates - argc) / 2, so we can fit all of the pair structs in each index of pairs[]
  20.  
  21. int pair_count;  // global variables: pair_count & candidate_count, representing the number of "pairs" & number of "candidates" in the arrays: pairs[] & candidates[]
  22. int candidate_count;
  23.  
  24. bool vote(int rank, string name, int ranks[]);  // function prototypes
  25. void record_preferences(int ranks[]);
  26. void add_pairs(void);
  27. void sort_pairs(void);
  28. void lock_pairs(void);
  29. void print_winner(void);
  30. bool check_cycle(int winner, int loser);
  31.  
  32. int main(int argc, string argv[])
  33. {
  34.     if (argc < 2)  // check for invalid usage
  35.     {
  36.         printf("Usage: tideman [candidate ...]\n");
  37.         return 1;
  38.     }
  39.  
  40.     candidate_count = argc - 1;  // populate array of candidates
  41.     if (candidate_count > MAX)
  42.     {
  43.         printf("Maximum number of candidates is %i\n", MAX);
  44.         return 2;
  45.     }
  46.  
  47.     for (int i = 0; i < candidate_count; i++) // loop through & populate the candidates[] array
  48.     {
  49.         candidates[i] = argv[i + 1]; // take user input for their "candidate" in argv (+1 to exclude ".\tideman") + store it in the candidate[] array
  50.     }
  51.  
  52.     for (int i = 0; i < candidate_count; i++)  // outer nested forloop, to go through 1 row (i) of locked[][] at a time
  53.     {
  54.         for (int j = 0; j < candidate_count; j++)  // inner nested loop, to go through every column (j) of locked[][] before the outer loop executes again, to check the next row
  55.         {
  56.             locked[i][j] = false;  // set the current element at locked[i][j] to FASLE
  57.         }
  58.     }
  59.  
  60.     pair_count = 0;  // set pairs_count at the start of main() to equal 0.
  61.     int voter_count = get_int("Number of voters: ");
  62.     printf("\n");
  63.  
  64.     for (int i = 0; i < voter_count; i++)  // outer nested forloop, to go through every voter declared
  65.     {
  66.         int ranks[candidate_count];  // creates a seperate array of ranks[] for the voter at "i", with as many elements equal to "candidate_count". ranks[i] is this voter's ith preference
  67.  
  68.         for (int j = 0; j < candidate_count; j++)  // inner loop to query for the current voters prefered candidates, until this matches the candidate_count. it will then store these in this voters ranks[] preferences
  69.         {
  70.             string name = get_string("Candiate prefered rank %i: ", j + 1);  // record the candidate rank for the current "voter" at "j" (+1 to make it count from voter 1 insteaf of voter 0).
  71.             if (!vote(j, name, ranks))  // the current value of "j" here represents the current voter being checked, the candidate "name" they picked & the current "ranks[]" 1d array for this voter. This is passed into vote()
  72.             {
  73.                 printf("Invalid vote.\n");
  74.                 return 3;
  75.             }
  76.         }
  77.         printf("Current ranks array %d %d %d:", ranks[0], ranks[1], ranks[2]);
  78.         printf("\n");
  79.         record_preferences(ranks);
  80.  
  81.     }
  82.     printf("\n");
  83.     add_pairs();
  84.     sort_pairs();
  85.     lock_pairs();
  86.     print_winner();
  87.     return 0;
  88. }
  89.  
  90.  
  91. bool vote(int rank, string name, int ranks[])  // update ranks given a new vote. this function takes in the arguments "rank", "name", and "ranks[]"" as mentioned on line 79
  92. {
  93.     for (int i = 0; i < candidate_count; i++)  // loop through against every potential candidate in the election
  94.     {
  95.         if (strcmp(candidates[i], name) == 0)  // check if the user's inputted "name" inpuuted on line 78 matches the current candidate in the candidates[] array looped through above. if TRUE (== 0)
  96.         {
  97.             ranks[rank] = i; // here "i" represents the index of current candidate in the candidates[] array. we update the ranks[] array with the ith candidate index, indicating this voter's current candidate preference to record.
  98.             return true;  // function will return TRUE after grabbing this ith candidate + storing it in the correct index of the ranks[] array (first candidate voter picked into ranks[0], second into ranks[1] etc)
  99.         }
  100.     }
  101.     return false;  // return FALSE if the above is not met, so this vote() function is looped through again in main()
  102. }
  103. void record_preferences(int ranks[])  // record each voter's preferences[][] by referencing their previous ranks[]
  104. {
  105.     printf("\n");
  106.     for (int i = 0; i < candidate_count; i++)   // outer forloop to increment "i" (for the row candidate) from 0, representing the current index of the candidate rank[] we want to reference in the 2d preferences[HERE][] array accurately
  107.     {
  108.         for (int j = 0; j < candidate_count; j++)  // inner forloop to increment a j counting variable (for the column candidate) from 0 to represent the current index of the candidate rank[] we want to reference in the 2d preferences[][HERE] array accurately
  109.         {
  110.             if (i < j)
  111.             {
  112.                 preferences[ranks[i]][ranks[j]]++; // add 1 tally mark to prefrences[i][j] in accordance to the current value of the counting variables i and j in the nested forloops, in context to the candidates in the 1d ranks[] array
  113.             }
  114.         }
  115.     }
  116. }
  117.  
  118. void add_pairs(void)  // Record pairs of candidates where one is preferred over the other
  119. {
  120.     for (int i = 0; i < candidate_count; i++) // outer forloop to increment a i counting variable (for the row candidate) from 0 to represent the current index of the candidate in the rows of preferences[HERE][]
  121.     {
  122.         for (int j = 0; j < candidate_count; j++)  // inner forloop to increment a j counting variable (for the column candidate) from 0 to represent the current index of the candidate in the columns of preferences[][HERE]
  123.         {
  124.             if (preferences[i][j] > preferences[j][i])  // if whatever is in preferences[i][j] has a greater value than in preferences[j][i] (that the candidate in preferences[i](Row) has more tally marks than the candidate in preference [j](Column)
  125.             {
  126.                 pairs[pair_count].winner = i;  // update the [current index] of the pairs[] array and set the value taken from preferences[i] (column) to be the winner
  127.                 pairs[pair_count].loser = j;  // update the [current index] of the pairs[] array and set the value taken from preferences[j] (row) to be the loser
  128.                 pair_count++; // update 1 count to the paircount to tally the total number of pairs counted in this program
  129.             }
  130.         }
  131.     }
  132.     return;
  133. }
  134.  
  135. void sort_pairs(void)
  136. {
  137.   while (1)  // this while loop is set to "true (1)" and it'll run forever until an exit condition is met
  138.   {
  139.       int swapped = 0;  // counting variable to indicate if a swap has been currently performed going through the bubble sort or not. This is set to 0 at the start of this while loop every time.
  140.       pair temp;  // declaring a temp variable to store variables we want to swap in
  141.  
  142.       for (int i = 0; i < pair_count -1; i++)  // Loop through entire array of pairs[]. In a bubble sort , we need to -1 off of the pair_count being checked against. Because there's nothing to compare the last element to.
  143.       {
  144.           // check if the margin difference between the candidate.winner - the candidate.loser in [i] is LESS THAN the margin difference between the candidate.winner - the candidate.loser in [i + 1]
  145.           if (preferences[pairs[i].winner][pairs[i].loser] - preferences[pairs[i].loser][pairs[i].winner] < preferences[pairs[i + 1].winner][pairs[i + 1].loser] - preferences[pairs[i].loser][pairs[i].winner])
  146.           {
  147.               temp = pairs[i];  // take the data in pairs[i] and move it inside of temp
  148.               pairs[i] = pairs[i + 1];  // take the data in pairs[i + 1] and move it to pairs[i]
  149.               pairs[i + 1] = temp;  // take the data we stores in temp and move it into [i +1] to complete the swap.
  150.               swapped = 1;  // update swapped to == 1 to indicate the full swap has been coomplete
  151.           }
  152.       }
  153.  
  154.       if (swapped == 0) // check if swapped equals "false"
  155.       {
  156.           break;  // if it does, break the loop
  157.       }
  158.   }
  159. }
  160.  
  161. void lock_pairs(void)  // lock pairs into the candidate graph in order, without creating cycles
  162. {
  163.     for (int i = 0; i < pair_count; i++)  // forloop through pairs[], to get the pairs with the highest strengh of victory (starting with pairs[0])
  164.     {
  165.         if (!check_cycle(pairs[i].winner, pairs[i].loser))  // if (no cycle will be created using check_cycles()) for the current .winner @ pairs[i] and .loser @ pairs[i]
  166.         {
  167.             locked[pairs[i].winner][pairs[i].loser] = true;  // set locked(for this)[.winner][.loser] at pairs[i] to TRUE, drawing a line;
  168.         }
  169.         printf("Locked[i][j] %s \n", locked[pairs[i].winner][pairs[i].loser] ? "true" : "false");
  170.     }
  171.     return;
  172. }
  173.  
  174. bool check_cycle(int start, int end)  // "int start" is "pairs[i].winner" & "int end" is the original calling function's loser
  175. {
  176.     // base condition to check IF() an edge is found between the current ending node & starting node being checked
  177.     // the base case can check IF an edge exists between two nodes anywhere but it can only do that with the help of the recursive function
  178.     // to loop through and first check if that edge exists between all possible 2 nodes in the graph first
  179.     if (locked[end][start] == true) // if (it finds an edge between the starting node and the ending node
  180.     {
  181.         return true; // return "true", indacating a edge exists between this starting node (candidate) and ending node (candidate)
  182.     }
  183.  
  184.     // recursive case
  185.     for (int i = 0; i < candidate_count; i++)   // loop through all the candidates in general, to see if an edge goes through (them as) any other nodes in the graph
  186.     {
  187.         if ((locked[i][start]) == true) // if an edge is found between the the ending node (indicated here by the candidate at [i] being looped through) and the starting node
  188.         {
  189.             /*
  190.              * the check_cycles() function then calls itself, it'll pass the previous "end node" from the line above as the new "start node", with "locked[(i)][]" as the new "start" parameter.
  191.              * it'll pass back and use the same "end node", which was originally passed into the function on line 182. (this remains unchanged). This allows us to keep track of the visited nodes + check
  192.                the entire graph for an edge between the original ending node, and a new starting node each time
  193.              */
  194.             if (check_cycle(i, end) == true)
  195.             {
  196.                 return true;
  197.             }
  198.         }
  199.     }
  200.     return false; // else return FALSE if no edges can be found betweeb the two nodes
  201.  }
  202.  
  203. void print_winner(void) // print the winner of the election
  204. {
  205.     bool winner;
  206.  
  207.     for (int i = 0; i < candidate_count; i++)  // nested outer loop, through all rows in locked[i][], checking for candidate [i]
  208.     {
  209.         winner = true; // set winner to TRUE on each passthrough of this loop
  210.  
  211.         for (int j = 0; j < candidate_count; j++) // nested inner loop, through all of the columns in locked[][] for candidate [j] with this inner nested loop
  212.         {
  213.             if (locked[j][i] == true) // if at anyt point when looping through the columns of candidates in [j], if we find any candidate at j with an arrow pointing ot them from a candidate at [i]
  214.             {
  215.                 winner = false; // assign the value of "false" to winner on this passthrough of this loop
  216.             }
  217.         }
  218.         // if after looping through the entire locked[][] 2d array column by column above and every index in locked [j][i] was set to "false" as we want
  219.         // determining candidate[j] has NO other candidates with an arrow pointing torwards them, winner is set to true
  220.         if (winner == true)
  221.         {
  222.             printf("%s\n", candidates[i]);
  223.         }
  224.     }
  225.     return;
  226. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement