/* J_score2.c Score display & txt output program for J-League result Practice of Information Processing, Fall 2023 Final Report Maximilian Fernaldy C2TB1702 */ #include // Standard input/output #include // Library for memory allocation and program control #define NAME_LENGTH 20 #define DATA_LEN 100 /* team score structure */ struct team_score{ char name[NAME_LENGTH]; /* team name */ int win; /* number of win */ int draw; /* number of draw */ int loss; /* number of lose */ int GF; /* goals for (scored)*/ int GA; /* goals against (conceded)*/ int score; /* win points */ int point_diff; /* goals difference */ }; typedef struct team_score SC; /*struct team_score is aliased as "SC" */ /* prototype declaration of functions */ SC *read_data(const char *file_path, int *number_of_teams); void calc_score(SC *team); void rank_score(SC table[], SC *rank_array[], int number_of_teams); void heapify(SC *rank_array[], int n, int i); void write_data(FILE *fout, SC *rank_array[], int number_of_teams); void swap_pointers(SC **pointerA, SC **pointerB); int get_number_of_teams(FILE *fin); int main(void) { /* variable declaration */ FILE *fout; /* (1) Reading file */ int number_of_teams; SC *table = read_data("J_result2023.csv", &number_of_teams); SC *rank_array[number_of_teams]; /* pointer array for sorting */ int i; /* Open reading file */ /* Open writing file */ fout = fopen("J_score3.txt","w"); // open output file /* (2)Calculating score */ for(i=0; i< number_of_teams; i++) { calc_score(&table[i]); } /* (3)Ranking based on score */ rank_score(table, rank_array, number_of_teams); /* (4) Writing ranking file in order*/ write_data(fout, rank_array, number_of_teams); /* closing process */ fclose(fout); /* close writing file */ return(0); } SC *read_data(const char *file_path, int *number_of_teams) { // Read data from csv file and store in table[] // Declare table to store data SC *table; // Open file for reading FILE *fin; if((fin = fopen(file_path,"r"))==NULL){ // open input file printf("Can't open result file. Make sure the csv file is in the working directory and formatted as \"J_resultYYYY.csv\".\n"); exit(1); } else { printf("Reading file \"%s\"...\n", file_path); } // Dynamically allocate memory for table int i = 0; *number_of_teams = get_number_of_teams(fin); table = malloc(sizeof(SC) * *number_of_teams); // Store data in array char buffer[DATA_LEN]; while (fgets(buffer, sizeof(buffer), fin) != NULL) { sscanf(buffer, "%[^,],%d,%d,%d,%d,%d", table[i].name, &table[i].win, &table[i].draw, &table[i].loss, &table[i].GF, &table[i].GA); i++; } // Close file and return storage table fclose(fin); return table; } int get_number_of_teams(FILE *fin) { // This function gets the selected file and returns how many lines are in the file. char buffer[DATA_LEN]; int number_of_teams = 0; while (fgets(buffer, sizeof(buffer), fin) != NULL) { number_of_teams++; } fseek(fin, 0, SEEK_SET); // return fgets to the first line return number_of_teams; } void calc_score(SC *team) { // Points = wins * 3 + draws * 1 + losses * 0 team->score = team->win * 3 + team->draw; // Point difference = Goals For - Goals Against team->point_diff = team->GF - team->GA; } void rank_score(SC table[], SC *rank_array[], int number_of_teams) { // Create array of pointers for (int i = 0; i < number_of_teams; i++) { rank_array[i] = &table[i]; } // Build min heap for (int i = number_of_teams/2 - 1; i >= 0; i--) { heapify(rank_array, number_of_teams, i); } /* At this point in the code, we have built a min heap, which means the smallest element is at the top of the heap, and no child node is smaller than the parent. However, it's not fully sorted yet. */ // Heap sort for (int n = number_of_teams - 1; n >= 0; n--) { /* Remove root node from heap by swapping with last element Then, heapify at root to get the smallest element at the root again Repeat until the heap is gone. */ swap_pointers(&rank_array[0], &rank_array[n]); heapify(rank_array, n, 0); } } void heapify(SC *rank_array[], int n, int i) { int lowest = i; // Initialize lowest as parent node int left = 2*i+1; // Index left child node int right = 2*i+2; // Index right child node if (left < n) { // If left child node should rank lower if (rank_array[left]->score < rank_array[lowest]->score) { // If score is lower lowest = left; } else if (rank_array[left]->score == rank_array[lowest]->score) { // If score is tied if (rank_array[left]->point_diff < rank_array[lowest]->point_diff) { // If point difference is lower lowest = left; } else if (rank_array[left]->point_diff == rank_array[lowest]->point_diff) { // If point difference is tied if (rank_array[left]->GF < rank_array[lowest]->GF) { // If less goals were scored lowest = left; } } } } if (right < n) { // If right child node should rank lower if (rank_array[right]->score < rank_array[lowest]->score) { // If score is lower lowest = right; } else if (rank_array[right]->score == rank_array[lowest]->score) { // If score is tied if (rank_array[right]->point_diff < rank_array[lowest]->point_diff) { // If point difference is lower lowest = right; } else if (rank_array[right]->point_diff == rank_array[lowest]->point_diff) { // If point difference is tied if (rank_array[right]->GF < rank_array[lowest]->GF) { // If less goals were scored lowest = right; } } } } // Swap if root is not the largest element, then continue heapify if (lowest != i) { // Swapping pointers around swap_pointers(&rank_array[lowest], &rank_array[i]); heapify(rank_array, n, lowest); } } void swap_pointers(SC **pointerA, SC **pointerB) { // this function swaps pointers. To do that, we pass in the pointer to the pointer. SC *temp = *pointerA; *pointerA = *pointerB; *pointerB = temp; } void write_data(FILE *fout, SC *rank_array[], int number_of_teams) { fprintf(fout, "| Rank | Team Name | Wins | Draws | Losses | Goals Scored | Goals Conceded | Points | Goal Difference |\n"); fprintf(fout, "|------|----------------------|------|-------|--------|--------------|----------------|--------|-----------------|\n"); for (int i = 0; i < number_of_teams; i++) { fprintf(fout, "| %-4d | %-20s | %4d | %5d | %6d | %12d | %14d | %6d | %15d |\n", i+1, rank_array[i]->name, rank_array[i]->win, rank_array[i]->draw, rank_array[i]->loss, rank_array[i]->GF, rank_array[i]->GA, rank_array[i]->score, rank_array[i]->point_diff); } }