Created
December 5, 2014 12:06
-
-
Save ElectricCoffee/c946d70c32360a5ce574 to your computer and use it in GitHub Desktop.
my first semester final exam program in imperative programming
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* Navn: Nikolaj Lepka | |
| Email: [email protected] | |
| Gruppe: A425b | |
| Studieretning: Datalogi */ | |
| #include <stdio.h> | |
| #include <stdlib.h> | |
| #include <string.h> | |
| #define DAYSIZE 4 | |
| #define TEAMSIZE 4 | |
| #define DATETIMESIZE 6 | |
| #define BUFFERSIZE 256 | |
| #define TEAMCOUNT 12 | |
| const char *TEAMNAMES[TEAMCOUNT] = {"AAB", "AGF", "BIF", "EFB", "FCK", "FCM", "FCN", "FCV", "OB", "RFC", "SDR", "VFF"}; | |
| typedef enum { MATCHES, TEAMS, NEITHER } buffer_type; | |
| typedef enum { LOSS = 0, TIE = 1, VICTORY = 3 } point_type; | |
| typedef enum { DEC = 12, JAN = 1, FEB = 2, | |
| MAR = 3, APR = 4, MAY = 5, | |
| JUN = 6, JUL = 7, AUG = 8, | |
| SEP = 9, OCT = 10, NOV = 11 } month; | |
| typedef struct { | |
| char weekday[DAYSIZE]; | |
| int day, month, hour, minute, year; | |
| char home_team[TEAMSIZE], away_team[TEAMSIZE]; | |
| int home_score, away_score; | |
| int spectator_count; | |
| int round; | |
| } match; | |
| typedef struct { | |
| char team_name[TEAMSIZE]; | |
| int home_wins, away_wins; | |
| int matches_played, matches_won, tied_matches, matches_lost; | |
| int goals_for, goals_against, goal_difference; | |
| int spectators; | |
| int points; | |
| } team; | |
| const team TEAMINIT = {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; | |
| typedef struct { | |
| char weekday[DAYSIZE], start_time[DATETIMESIZE], end_time[DATETIMESIZE]; | |
| } time_span; | |
| void print_instructions(); | |
| size_t count_matches(FILE *); | |
| void extract_data(const size_t, FILE *, match *); | |
| void generate_team_stats(const size_t, const match *, team *); | |
| void init_teams(team *); | |
| int get_team_index(const char *); | |
| int select_and_print(const size_t, const match *, const team *, const int); | |
| void print_matches(const size_t, const match *); | |
| void print_teams(const size_t, const team *); | |
| void print_all(const size_t, const match *, const team *); | |
| size_t get_score_seven_or_higher(const size_t, const match *, match *); /* 1 */ | |
| size_t get_most_goals(const size_t, const match *, match *); /* 2 */ | |
| size_t get_most_matches_as_away(const team *, team *); /* 3 */ | |
| size_t get_team_with_least_spectators(const team *, team *); /* 4 */ | |
| size_t get_all_matches_in_timeframe(const size_t, const match *, const time_span , match *); /* 5 */ | |
| size_t get_ordered_table_of_standings(const team *, team *); /* 6 */ | |
| int compare_teams(const void *, const void *); | |
| int main(int argc, const char **argv) { | |
| FILE *league_file = fopen("superliga-2013-2014", "r"); | |
| match *matches; | |
| team teams[TEAMCOUNT]; | |
| int match_count, problem_number; | |
| if (league_file) { /* if the file successfully opened, check if a --print argument is present or not */ | |
| match_count = count_matches(league_file); | |
| matches = calloc(match_count, sizeof(match)); | |
| extract_data(match_count, league_file, matches); | |
| generate_team_stats(match_count, matches, teams); | |
| fclose(league_file); | |
| if (argc == 2 && strcmp(argv[1], "--print") == 0) print_all(match_count, matches, teams); | |
| else { | |
| puts("Hello, and welcome to the exam program for IMPR 2014"); | |
| do { | |
| print_instructions(); | |
| scanf("%i", &problem_number); | |
| } while ((select_and_print(match_count, matches, teams, problem_number)) == 0xBAD5EED); | |
| } | |
| } | |
| else { /* if it didn't open successfully, terminate the program */ | |
| puts("Could not open file. Terminating application."); | |
| exit(EXIT_FAILURE); | |
| } | |
| exit(EXIT_SUCCESS); | |
| } | |
| /* add count matches and extract data here */ | |
| size_t count_matches(FILE *file) { | |
| char buffer[BUFFERSIZE]; | |
| size_t line_count = 0; | |
| rewind(file); /* rewinding just in case */ | |
| while (fgets(buffer, BUFFERSIZE, file) != NULL) { | |
| /* if it successfully finds something on the line, increment the counter */ | |
| if(sscanf(buffer, "%*s") == 0) line_count++; | |
| } | |
| return line_count; | |
| } | |
| /* extracts the data from the file, | |
| and loads it into an array of structs matching the nonempty lines */ | |
| void extract_data(const size_t match_count, FILE *league_file, match *matches) { | |
| int thousands, hundreds, i, current_round = 1, current_match = 0, scanned_items; | |
| char buffer[BUFFERSIZE]; | |
| match temp_match; | |
| rewind(league_file); | |
| for (i = 0; fgets(buffer, BUFFERSIZE, league_file) != NULL; i++) { | |
| /* printf("read: %s\n", buffer); */ | |
| scanned_items = sscanf(buffer, "%s %d/%d %d.%d %s - %s %d - %d %d.%d", | |
| temp_match.weekday, &temp_match.day, &temp_match.month, | |
| &temp_match.hour, &temp_match.minute, | |
| temp_match.home_team, temp_match.away_team, | |
| &temp_match.home_score, &temp_match.away_score, | |
| &thousands, &hundreds); | |
| temp_match.spectator_count = (thousands * 1000) + hundreds; | |
| temp_match.year = temp_match.month >= JUL ? 2013 : 2014; | |
| temp_match.round = current_round; | |
| /* if everything was successfully read, copy the temp onto the array */ | |
| if(scanned_items == 11) { | |
| matches[current_match] = temp_match; | |
| current_match++; | |
| } | |
| else if (scanned_items == -1) { | |
| current_round++; | |
| } | |
| else { | |
| puts("FORMAT ERROR"); | |
| } | |
| } | |
| } | |
| /* uses the matches read from the input file to generate the statistics of the individual teams, | |
| the function updates the statistics of the current home and away team at the same time */ | |
| void generate_team_stats(const size_t match_count, const match *matches, team *teams) { | |
| int match_index, home_team_index, away_team_index, team_index; | |
| for (team_index = 0; team_index < TEAMCOUNT; team_index++) { | |
| teams[team_index] = TEAMINIT; /* initialise all the fields with 0s so the increment doesn't fail */ | |
| strcpy(teams[team_index].team_name, TEAMNAMES[team_index]); /* sets all the team names in the newly initialised teams */ | |
| } | |
| for (match_index = 0; match_index < match_count; match_index++) { | |
| home_team_index = get_team_index(matches[match_index].home_team); | |
| away_team_index = get_team_index(matches[match_index].away_team); | |
| teams[home_team_index].matches_played++; | |
| teams[away_team_index].matches_played++; | |
| if (matches[match_index].home_score > matches[match_index].away_score) { | |
| teams[home_team_index].matches_won++; | |
| teams[home_team_index].home_wins++; | |
| teams[away_team_index].matches_lost++; | |
| } | |
| else if (matches[match_index].home_score < matches[match_index].away_score) { | |
| teams[home_team_index].matches_lost++; | |
| teams[away_team_index].matches_won++; | |
| teams[away_team_index].away_wins++; | |
| } | |
| else { | |
| teams[home_team_index].tied_matches++; | |
| teams[away_team_index].tied_matches++; | |
| } | |
| teams[home_team_index].goals_for += matches[match_index].home_score; | |
| teams[home_team_index].goals_against += matches[match_index].away_score; | |
| teams[away_team_index].goals_for += matches[match_index].away_score; | |
| teams[away_team_index].goals_against += matches[match_index].home_score; | |
| teams[home_team_index].goal_difference = teams[home_team_index].goals_for - teams[home_team_index].goals_against; | |
| teams[away_team_index].goal_difference = teams[away_team_index].goals_for - teams[away_team_index].goals_against; | |
| teams[home_team_index].points = VICTORY * teams[home_team_index].matches_won + teams[home_team_index].tied_matches; | |
| teams[away_team_index].points = VICTORY * teams[away_team_index].matches_won + teams[away_team_index].tied_matches; | |
| teams[home_team_index].spectators += matches[match_index].spectator_count; | |
| teams[away_team_index].spectators += matches[match_index].spectator_count; | |
| } | |
| } | |
| /* gets the index of a team in accordance to the TEAMNAMES array, | |
| this ensures you always get the same team on a given team name */ | |
| int get_team_index(const char *team_name) { | |
| int i; | |
| for (i = 0; i < TEAMCOUNT; i++) | |
| if (strcmp(team_name, TEAMNAMES[i]) == 0) return i; | |
| return 0; /* if the team name doesn't match anything (shouldn't happen) */ | |
| } | |
| /* prints all the instructions */ | |
| void print_instructions() { | |
| puts("Please select one of the numbers below to select a problem to be solved and printed."); | |
| puts("You can re-run the program with a \"--print\" flag to have it print all the results."); | |
| puts("1) Find and print the matches that scored 7 or more goals."); | |
| puts("2) Find and print the match with most goals, and print the number of goals."); | |
| puts("3) Find the teams that won most matches as the away team."); | |
| puts("4) Find the team that collectively had the least spectators in the entire tournament."); | |
| puts("5) Find and print all matches for a given time-span and day."); | |
| puts("6) Calculate and print a table of the standings in the final round."); | |
| puts("0) Exit the program."); | |
| } | |
| /* interprets the user input and calls the corresponding function */ | |
| int select_and_print(const size_t match_count, const match *matches, const team *teams, const int problem_number) { | |
| match match_buffer[BUFFERSIZE]; | |
| team team_buffer[BUFFERSIZE]; | |
| time_span time_and_day; | |
| size_t result_size; | |
| buffer_type buff = NEITHER; | |
| switch (problem_number) { | |
| case 0: puts("Good bye!"); break; | |
| case 1: | |
| puts("All the matches with a score of 7 or higher:"); | |
| result_size = get_score_seven_or_higher(match_count, matches, match_buffer); | |
| buff = MATCHES; | |
| break; | |
| case 2: | |
| puts("The match with the most goals:"); | |
| result_size = get_most_goals(match_count, matches, match_buffer); | |
| buff = MATCHES; | |
| break; | |
| case 3: | |
| puts("All the teams with most won matches as the away team:"); | |
| result_size = get_most_matches_as_away(teams, team_buffer); | |
| buff = TEAMS; | |
| break; | |
| case 4: | |
| puts("Team with least spectators overall:"); | |
| result_size = get_team_with_least_spectators(teams, team_buffer); | |
| buff = TEAMS; | |
| break; | |
| case 5: | |
| printf("Please enter a 3-letter weekday, and two timestamps in the format hh.mm: "); | |
| scanf("%3s %5s %5s", time_and_day.weekday, time_and_day.start_time, time_and_day.end_time); | |
| result_size = get_all_matches_in_timeframe(match_count, matches, time_and_day, match_buffer); | |
| buff = MATCHES; | |
| break; | |
| case 6: | |
| puts("Table of standings ordered by score: "); | |
| result_size = get_ordered_table_of_standings(teams, team_buffer); | |
| buff = TEAMS; | |
| break; | |
| default: | |
| puts("Invalid input, please try again"); | |
| return 0xBAD5EED; /* is read as "bad seed" */ | |
| } | |
| if (buff == MATCHES) print_matches(result_size, match_buffer); | |
| else if (buff == TEAMS) print_teams(result_size, team_buffer); | |
| else { /* do nothing */ } | |
| return 0x600D5EED; /* is read as "good seed" */ | |
| } | |
| /* prints all the results of all the functions the same way select_and_print does it */ | |
| void print_all(const size_t match_count, const match *matches, const team *teams) { | |
| match match_buffer[BUFFERSIZE]; | |
| team team_buffer[BUFFERSIZE]; | |
| time_span time_and_day = {"Fre", "18.05", "19.05"}; | |
| size_t result_size; | |
| puts("Problem 1 - greater than 7"); | |
| result_size = get_score_seven_or_higher(match_count, matches, match_buffer); | |
| print_matches(result_size, match_buffer); | |
| puts("Problem 2 - most goals"); | |
| result_size = get_most_goals(match_count, matches, match_buffer); | |
| print_matches(result_size, match_buffer); | |
| puts("Problem 3 - most as away"); | |
| result_size = get_most_matches_as_away(teams, team_buffer); | |
| print_teams(result_size, team_buffer); | |
| puts("Problem 4 - least spectators"); | |
| result_size = get_team_with_least_spectators(teams, team_buffer); | |
| print_teams(result_size, team_buffer); | |
| puts("Problem 5 - all between 18:05 and 19:05 on a friday"); | |
| result_size = get_all_matches_in_timeframe(match_count, matches, time_and_day, match_buffer); | |
| print_matches(result_size, match_buffer); | |
| puts("Problem 6 - table of standings"); | |
| result_size = get_ordered_table_of_standings(teams, team_buffer); | |
| print_teams(result_size, team_buffer); | |
| } | |
| /* prints all the matches in a given array of matches */ | |
| void print_matches(const size_t result_size, const match *matches) { | |
| int i; | |
| puts("round | day | date | time | home - away | hg - ag | spectators"); | |
| for (i = 0; i < result_size; i++) { | |
| printf("%5i | %3s | %4i-%02i-%02i | %02i:%02i | %4s - %-4s | %2i - %-2i | %6i\n", | |
| matches[i].round, | |
| matches[i].weekday, matches[i].year, matches[i].month, matches[i].day, | |
| matches[i].hour, matches[i].minute, | |
| matches[i].home_team, matches[i].away_team, | |
| matches[i].home_score, matches[i].away_score, | |
| matches[i].spectator_count); | |
| } | |
| puts(""); | |
| } | |
| /* prints all the teams in a given array of teams */ | |
| void print_teams(const size_t result_size, const team *teams) { | |
| int i; | |
| puts("team | matches | win | tie | loss | gf - ga | diff | score | spectators"); | |
| for (i = 0; i < result_size; i++) { | |
| printf("%4s | %7i | %3i | %3i | %4i | %2i - %2i | %+4d | %5i | %i\n", | |
| teams[i].team_name, | |
| teams[i].matches_played, teams[i].matches_won, teams[i].tied_matches, teams[i].matches_lost, | |
| teams[i].goals_for, teams[i].goals_against, teams[i].goal_difference, | |
| teams[i].points, teams[i].spectators); | |
| } | |
| puts(""); | |
| } | |
| /* 1) gets all the matches with a total score of 7 or higher */ | |
| size_t get_score_seven_or_higher(const size_t match_count, const match *matches, match *buffer) { | |
| size_t match_index, buffer_index = 0; | |
| for (match_index = 0; match_index < match_count; match_index++) { | |
| if ((matches[match_index].home_score + matches[match_index].away_score) >= 7) { | |
| buffer[buffer_index] = matches[match_index]; | |
| buffer_index++; | |
| } | |
| } | |
| /* the buffer index is returned so we have a stopping point in the output buffer when the data is printed, | |
| without it, the entire buffer would be printed, including whatever garbage left in it */ | |
| return buffer_index; | |
| } | |
| /* 2) gets the round with the most goals in the tournament */ | |
| size_t get_most_goals(const size_t match_count, const match *matches, match *buffer) { | |
| int current_round = matches[0].round, current_match, goal_accumulator = 0, most_goals = 0, highest_round, buffer_max = 0; | |
| for (current_match = 0; current_match < match_count; current_match++) { | |
| /* if the round of the current match matches the current round, add the combined goals to the accumulator */ | |
| if (matches[current_match].round == current_round) { | |
| goal_accumulator += (matches[current_match].home_score + matches[current_match].away_score); | |
| } | |
| else { | |
| /* set the highest round to be the current round, if its accumulated goals exceed the existing high */ | |
| highest_round = most_goals < goal_accumulator ? current_round : highest_round; | |
| /* set the most goals to be the accumulated number, if the accumulated number exceeds the existing high */ | |
| most_goals = most_goals < goal_accumulator ? goal_accumulator : most_goals; | |
| /* reset the accumulator */ | |
| goal_accumulator = 0; | |
| /* update the current round */ | |
| current_round = matches[current_match].round; | |
| } | |
| } | |
| /* whithout these, the last round won't be checked and added */ | |
| highest_round = most_goals < goal_accumulator ? current_round : highest_round; | |
| most_goals = most_goals < goal_accumulator ? goal_accumulator : most_goals; | |
| /* add all the matches of the round with the highest score to the buffer */ | |
| for (current_match = 0; current_match < match_count; current_match++) { | |
| if (matches[current_match].round == highest_round) { | |
| buffer[buffer_max] = matches[current_match]; | |
| buffer_max++; | |
| } | |
| } | |
| return buffer_max; | |
| } | |
| /* 3) gets the teams that have the more wins as the away team than as the home team */ | |
| size_t get_most_matches_as_away(const team *teams, team *buffer) { | |
| int i, buffer_max = 0; | |
| for (i = 0; i < TEAMCOUNT; i++) { | |
| if (teams[i].away_wins > teams[i].home_wins) { | |
| buffer[buffer_max] = teams[i]; | |
| buffer_max++; | |
| } | |
| } | |
| return buffer_max; | |
| } | |
| /* 4) gets the team that collectively has had the least number of spectators in the entire tournament */ | |
| size_t get_team_with_least_spectators(const team *teams , team *output) { | |
| int spectators = 6000000, team_index, i; | |
| for (i = 0; i < TEAMCOUNT; i++) { | |
| if (teams[i].spectators < spectators) { | |
| spectators = teams[i].spectators; | |
| team_index = i; | |
| } | |
| } | |
| output[0] = teams[team_index]; | |
| return 1; /* we only need one team, the return is here for compatibility with print_teams */ | |
| } | |
| /* 5) gets all the matches within a given timeframe */ | |
| size_t get_all_matches_in_timeframe(const size_t match_count, const match *matches, const time_span datetime, match *buffer) { | |
| int start_hour, end_hour, start_minute, end_minute, i, j = 0, after_starttime, before_endtime; | |
| sscanf(datetime.start_time, "%d.%d", &start_hour, &start_minute); | |
| sscanf(datetime.end_time, "%d.%d", &end_hour, &end_minute); | |
| for (i = 0; i < match_count; i++) { | |
| after_starttime = matches[i].hour >= start_hour; | |
| if (matches[i].hour == start_hour) after_starttime = matches[i].minute >= start_minute; | |
| before_endtime = matches[i].hour <= end_hour; | |
| if (matches[i].hour == end_hour) before_endtime = matches[i].minute >= end_minute; | |
| if (strcmp(matches[i].weekday, datetime.weekday) == 0 && after_starttime && before_endtime) { | |
| buffer[j] = matches[i]; | |
| j++; | |
| } | |
| } | |
| return j; | |
| } | |
| /* 6) gets all the teams ordered by score */ | |
| size_t get_ordered_table_of_standings(const team *teams, team *buffer) { | |
| memcpy(buffer, teams, TEAMCOUNT * sizeof(team)); | |
| qsort(buffer, TEAMCOUNT, sizeof(team), compare_teams); | |
| return TEAMCOUNT; /* for compatibility with the print_teams function */ | |
| } | |
| /* compares two teams by their score */ | |
| int compare_teams(const void *left, const void *right) { | |
| team | |
| *a = (team *) left, | |
| *b = (team *) right; | |
| if (a->points > b->points) return -1; | |
| else if (a->points < b->points) return 1; | |
| else return 0; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment