Notifications



Goals for this homework

  • Gain experience with structs and pointers.

You are expected to complete this assignment individually. If you need help, you are invited to come to office hours and/or ask questions on piazza. Clarification questions about the assignments may be asked publicly. Once you have specific bugs related to your code, make the posts private.

In this project, you will load data of highly ranked songs in spotify from a csv(comma separated values) file. You will implement some functions to do some simple data analysis. The data file is provided here: data.csv. Each line corresponds to a record of a song. Each line comprises the following fields:

  1. rank: the rank of the song on that day
  2. song: the name of the song
  3. artist: the artist that sings this song
  4. streams: number of streams
  5. URL: the URL of the song
  6. date: the date
  7. region: the region, all data are for the US in our file

Here are some samples of lines you will see in data.csv.

1,Bad and Boujee (feat. Lil Uzi Vert),Migos,1371493,https://open.spotify.com/track/4Km5HrUvYTaSUfiSGPJeQR,2017-01-01,us
2,Fake Love,Drake,1180074,https://open.spotify.com/track/343YBumqHu19cGoGARUTsd,2017-01-01,us
3,Starboy,The Weeknd,1064351,https://open.spotify.com/track/5aAx2yezTd8zXrkmtKl66Z,2017-01-01,us

We won't need all the fields in the csv file. The fields we will work with in this project are: rank, song, artist and date. We use the following structure record to store these four fields in a single line of the csv file.

typedef struct { int position; char* song; char* artist; struct tm* date; } record;

struct tm is a structure to store date and time information, defined in time.h. It is sufficient to finish this assignment if you understand how we use struct tm in our provided code.

We provide the implementation of reading data from the csv file, storing data inside a 2d array of record*, print the data and free the variable memories. The files are provided hw4_provided.h, hw4_provided.c and hw4_main.c.

Basically, we define a 2 dimensional array of record*, and that is why you see

record*** read_spotify_data(char* filename, int* num_days, int* num_records_per_day, struct tm* first_day);

This function reads data from a csv file named "filename" and store them in the 2d array. The first dimension represents the date, and the second dimension represents the rank of the song. The first line of the csv file will be the first date to read, number of (consecutive) days to read, and number of records per day. Each element in the 2d array is a pointer to a record. Please remember that some elements of the 2d array may be a NULL pointer as the data may not in the csv file.

You should be able to create a Makefile and write down the command to compile the source code.

Make sure that you can compile and execute our provided code. Read the code to understand what the code is doing. Especially how data is stored and accessed in the variable record*** rs.

You should submit four files for this assignment ( hw4.h, hw4.c, hw4_main.c, and Makefile) in your subversion repository as directed below.

Set Up

You need a hw4.c and hw4.h file for this portion.

You need to add the skeleton code so that your program will minimally execute. You must do this in case you do not complete your assignment. Our testing infrastructure needs to compile and execute even if you did not complete the entire assignment. Refer to past assignments on how to make skeleton code.

Problem 1: find_highest_record_by_date

record* find_highest_record_by_date(const char* date, record*** rs, int num_days);

Given a date (string), find the record of song ranked first on that date. For example, given "2017-04-07", your code should be able to find the following record: "1, HUMBLE., Kendrick Lamar, 2017-04-07" (printed out by print_record).

Return the pointer of that record.

If you don't know how to convert a string to struct tm*, please read function "record* read_record(char* line)" in hw4_provided.c. There is a line of code doing that.

Problem 2: find_artist_highest_rank

record* find_artist_highest_rank(const char* artist, record*** rs, int num_days, int num_records_per_day);

Given an artist (string), retrieve the highest ranked record of that artist. If multiple highest ranked records are available, only return the first record. For example, given artist "Bruno Mars", your code should retrieve the following record: "3, That's What I Like, Bruno Mars, 2017-03-03".

Return the pointer to that record.

Problem 3: score_artist

double score_artist(const char* artist, record*** rs, int num_days, int num_records_per_day);

We define a way to assign scores to artists. The artist gets point by ranking at top 20, the exact points are as following:

1st: 50
2nd: 40
3rd: 30
4th: 20
5th: 16
6th: 15
7th: 14
...
20th: 1

Now given an artist (string), calculate the score for that artist and return that score. parameter record*** rs is the 2d record pointer array, int num_days is the number of days we have in our array, and int num_records_per_day is the number of records per day.

Problem 4: score_song

double score_song(const char* song, record*** rs, int num_days, int num_records_per_day);

Similar to problem 3, we define a way to assign scores to songs. A song gets points by ranked top 20 on a day. The way we assign scores to songs follows the exact rule as scoring artists. Implement this function to return the score (double) given a song (string).

Testing

Create test cases for the functions you just created using the method we introduced in warmup4 and prelab4. hw4_provided.h and hw4_provided.c. Note that the struct is declared in this .h file, so do not redeclare the struct in your own .h file. Instead, you need to
#include "hw4_provided.h"
before your hw4.h file.

Add test cases into testscript you created in warmup4.

You will send in command-line arguments with the function being tested, the function parameters, and expected results. You will read in the command-line arguments, determine which function to test, run that test, then compare the actual result with the expected result.

Essentially your test program checks the command-line argument of function naem and function parameters, tries to call the functions accordingly, gets the result and compare with the expected result to determine whether your functions work correctly.

For example, if you run

./hw4_main find_artist_highest_rank "Bruno Mars" "3, That's What I Like, Bruno Mars, 2017-03-03"
If your function works correctly, your program should output something like
find_artist_highest_rank "Bruno Mars" expected: 3, That's What I Like, Bruno Mars, 2017-03-03 actual: 3, That's What I Like, Bruno Mars, 2017-03-03 SUCCESS
If your function does not work as expected, your test program should print
find_artist_highest_rank "Bruno Mars" expected: 3, That's What I Like, Bruno Mars, 2017-03-03 actual: [you got something unexpected] FAILURE
Your message needs to contain: function name, parameters, the expected output vs actual output, and success or failure.

Note that for problem 1 and 2, since the function return type is record*, you need to call print_record to get the text description of the record and compare with the expected result. For problem 3 and 4, since they are doubles you can directly compare them. However, be careful when you compare two doubles, you may not use == directly to determine whether two doubles are equal.

Submit

At this point, you should have done the following:
  • Created four files and filled in the proper information: hw4.h, hw4.c, hw4_main.c, testscript inside your hw4 directory. Make sure that before you execute this command, you have already added your hw4 directory.
  • $ svn add hw4.h hw4.c hw4_main.c testscript
    
  • Implemented all of your functions. If not, you at least need skeletons of your functions so that our automated tests will compile for the functions you did write.
  • Compiled your executable manually and with the Makefile
  • Implemented your test cases
  • Executed your code
  • Debugged your code
  • $ svn commit -m "hw4 complete"