Advertisement
drankinatty

PSet3 - Tideman (one approach)

Apr 26th, 2022 (edited)
1,711
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 6.95 KB | None | 0 0
  1. #include <cs50.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <string.h>
  5.  
  6. // Max number of candidates
  7. #define MAX 9
  8.  
  9. // preferences[i][j] is number of voters who prefer i over j
  10. int preferences[MAX][MAX];
  11.  
  12. // locked[i][j] means i is locked in over j
  13. bool locked[MAX][MAX];
  14.  
  15. // Each pair has a winner, loser
  16. typedef struct
  17. {
  18.     int winner;
  19.     int loser;
  20. }
  21. pair;
  22.  
  23. // Array of candidates
  24. string candidates[MAX];
  25. pair pairs[MAX * (MAX - 1) / 2];
  26.  
  27. int pair_count;
  28. int candidate_count;
  29.  
  30. // Function prototypes
  31. bool vote(int rank, string name, int ranks[]);
  32. void record_preferences(int ranks[]);
  33. void add_pairs(void);
  34. void sort_pairs(void);
  35. void lock_pairs(void);
  36. void print_winner(void);
  37.  
  38. int main(int argc, string argv[])
  39. {
  40.     // Check for invalid usage
  41.     if (argc < 2)
  42.     {
  43.         printf("Usage: tideman [candidate ...]\n");
  44.         return 1;
  45.     }
  46.  
  47.     // Populate array of candidates
  48.     candidate_count = argc - 1;
  49.     if (candidate_count > MAX)
  50.     {
  51.         printf("Maximum number of candidates is %i\n", MAX);
  52.         return 2;
  53.     }
  54.     for (int i = 0; i < candidate_count; i++)
  55.     {
  56.         candidates[i] = argv[i + 1];
  57.     }
  58.  
  59.     // Clear graph of locked in pairs
  60.     for (int i = 0; i < candidate_count; i++)
  61.     {
  62.         for (int j = 0; j < candidate_count; j++)
  63.         {
  64.             locked[i][j] = false;
  65.         }
  66.     }
  67.  
  68.     pair_count = 0;
  69.     int voter_count = get_int("Number of voters: ");
  70. #ifdef REDIR
  71. printf ("%d\n", voter_count);
  72. #endif
  73.     // Query for votes
  74.     for (int i = 0; i < voter_count; i++)
  75.     {
  76.         // ranks[i] is voter's ith preference
  77.         int ranks[candidate_count];
  78.  
  79.         // Query for each rank
  80.         for (int j = 0; j < candidate_count; j++)
  81.         {
  82.             string name = get_string("Rank %i: ", j + 1);
  83.  
  84. #ifdef REDIR
  85. printf ("%-8s", name);
  86. #endif
  87.             if (!vote(j, name, ranks))
  88.             {
  89.                 printf("Invalid vote.\n");
  90.                 return 3;
  91.             }
  92.         }
  93.  
  94.         record_preferences(ranks);
  95.  
  96.         printf("\n");
  97.     }
  98.  
  99.     puts ("\n(A)lice (B)ob (C)harlie  -  preferences\n\n   A  B  C");
  100.     for (int k = 0; k < candidate_count; k++) {
  101.         putchar ('A' + k);
  102.         for (int l = 0; l < candidate_count; l++)
  103.             printf ("  %d", preferences[k][l]);
  104.         putchar ('\n');
  105.     }
  106.     putchar ('\n');
  107.  
  108.     add_pairs();
  109.  
  110.     puts ("Pre-sort Pair Order:");
  111.     for (int k = 0; k < pair_count; k++)
  112.         printf ("   (%c, %c)\n", 'A' + pairs[k].winner, 'A' + pairs[k].loser);
  113.     putchar ('\n');
  114.  
  115.     sort_pairs();
  116.  
  117.     puts ("Post-sort Pair Order:");
  118.     for (int k = 0; k < pair_count; k++)
  119.         printf ("   (%c, %c)\n", 'A' + pairs[k].winner, 'A' + pairs[k].loser);
  120.  
  121.     lock_pairs();
  122.  
  123.     putchar ('\n');
  124.  
  125.     print_winner();
  126.  
  127.     return 0;
  128. }
  129.  
  130. // Update ranks given a new vote
  131. bool vote(int rank, string name, int ranks[])
  132. {
  133.     int idx = 0;
  134.     for (; idx < candidate_count; idx++)
  135.         if (strcmp (name, candidates[idx]) == 0)
  136.             break;
  137.     if (idx == candidate_count)
  138.         return false;
  139.  
  140.     ranks[rank] = idx;
  141.  
  142.     return true;
  143. }
  144.  
  145. // Update preferences given one voter's ranks
  146. void record_preferences(int ranks[])
  147. {
  148.     for (int i = 0; i < candidate_count; i++)
  149.         for (int j = i + 1; j < candidate_count; j++)
  150.             preferences[ranks[i]][ranks[j]]++;
  151. }
  152.  
  153. // Record pairs of candidates where one is preferred over the other
  154. void add_pairs(void)
  155. {
  156.     for (int i = 0; i < candidate_count; i++)
  157.         for (int j = 0; j < candidate_count; j++)
  158.             if (j != i && preferences[i][j] > preferences[j][i]) {
  159.                 pairs[pair_count].winner = i;
  160.                 pairs[pair_count++].loser = j;
  161.             }
  162. }
  163.  
  164. int cmppairs (const void *a, const void *b)
  165. {
  166.     const pair *pa = a, *pb = b;
  167.     /* sort descending on preferences value (conditional prevents possible overflor)
  168.      * equivalent to:
  169.      *   preferences[pa->winner][pa->loser] - preferences[pb->winner][pb->loser]
  170.      */
  171.     return (preferences[pa->winner][pa->loser] < preferences[pb->winner][pb->loser]) -
  172.            (preferences[pa->winner][pa->loser] > preferences[pb->winner][pb->loser]);
  173. }
  174.  
  175. // Sort pairs in decreasing order by strength of victory
  176. void sort_pairs(void)
  177. {
  178.     qsort (pairs, pair_count, sizeof *pairs, cmppairs);
  179. }
  180.  
  181. // Lock pairs into the candidate graph in order, without creating cycles
  182. void lock_pairs(void)
  183. {
  184.     int cycle[pair_count];  /* VLA to capture occurrence of arrow for candidate */
  185.     memset (cycle, 0, pair_count * sizeof *cycle);
  186.  
  187.     for (int i = 0; i < pair_count; i++) {
  188.         if (i == pair_count - 1) {              /* if last pair, check cycle */
  189.             int sum = 0;
  190.             /* sum current candidates with arrows */
  191.             for (int j = 0; j < pair_count; j++)
  192.                 sum += cycle[j];
  193.             /* if single candidate unlocked & arrow would lock candidate's edge */
  194.             if (sum == i && cycle[pairs[i].loser] == 0)
  195.                 break;  /* don't lock edge */
  196.         }
  197.         /* mark arrow (edge) on losing candidate, so source stays zero */
  198.         locked[pairs[i].loser][pairs[i].winner] = true;
  199.         cycle[pairs[i].loser] = 1;
  200.     }
  201. }
  202.  
  203. // Print the winner of the election
  204. void print_winner(void)
  205. {
  206.     for (int i = 0; i < candidate_count; i++) {
  207.         printf ("%-8s", candidates[i]);
  208.         for (int j = 0; j < candidate_count; j++)
  209.             printf ("  %d", locked[i][j] ? 1 : 0);
  210.         putchar ('\n');
  211.     }
  212.  
  213.     for (int i = 0; i < candidate_count; i++) {
  214.         int j = 0;
  215.         for (; j < candidate_count; j++)
  216.             if (locked[i][j])
  217.                 break;
  218.         if (j == candidate_count) {
  219.             printf ("\nWinner: %s\n", candidates[i]);
  220.             return;
  221.         }
  222.     }
  223. }
  224.  
  225. /**
  226. Compile to allow redirecting file as input:
  227.  
  228. gcc -Wall -Wextra -pedantic -Wshadow -std=c11 -Ofast -DREDIR -o tideman tideman.c -lcs50
  229.  
  230. Testing data file "votes.txt":
  231.  
  232. 9
  233. Alice
  234. Bob
  235. Charlie
  236. Alice
  237. Bob
  238. Charlie
  239. Alice
  240. Bob
  241. Charlie
  242. Bob
  243. Charlie
  244. Alice
  245. Bob
  246. Charlie
  247. Alice
  248. Charlie
  249. Alice
  250. Bob
  251. Charlie
  252. Alice
  253. Bob
  254. Charlie
  255. Alice
  256. Bob
  257. Charlie
  258. Alice
  259. Bob
  260.  
  261. Example Use/Output:
  262.  
  263. ./tideman Alice Bob Charlie < votes.txt
  264. Number of voters: 9
  265. Rank 1: Alice   Rank 2: Bob     Rank 3: Charlie
  266. Rank 1: Alice   Rank 2: Bob     Rank 3: Charlie
  267. Rank 1: Alice   Rank 2: Bob     Rank 3: Charlie
  268. Rank 1: Bob     Rank 2: Charlie Rank 3: Alice
  269. Rank 1: Bob     Rank 2: Charlie Rank 3: Alice
  270. Rank 1: Charlie Rank 2: Alice   Rank 3: Bob
  271. Rank 1: Charlie Rank 2: Alice   Rank 3: Bob
  272. Rank 1: Charlie Rank 2: Alice   Rank 3: Bob
  273. Rank 1: Charlie Rank 2: Alice   Rank 3: Bob
  274.  
  275. (A)lice (B)ob (C)harlie  -  preferences
  276.  
  277.    A  B  C
  278. A  0  7  3
  279. B  2  0  5
  280. C  6  4  0
  281.  
  282. Pre-sort Pair Order:
  283.    (A, B)
  284.    (B, C)
  285.    (C, A)
  286.  
  287. Post-sort Pair Order:
  288.    (A, B)
  289.    (C, A)
  290.    (B, C)
  291.  
  292. Alice     0  0  1
  293. Bob       1  0  0
  294. Charlie   0  0  0
  295.  
  296. Winner: Charlie
  297.  
  298. */
  299.  
  300.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement