Lab 3: Linked Lists of TTC Trains and Passengers

This lab is part of Assignment 1. You are to complete the exercises here before arriving in lab on Monday/Tuesday. In lab, you and your partner will demonstrate your code to your TA, and get feedback. Your revised code is due on February 7 at noon.

Labs 3 and 4, together, form a simulation of the Bloor-Danforth TTC line. In Lab 3, we will implement the code for the trains and the passengers. In Lab 4, we will implement the code for the stations, and put everything together in a simulation.

As always, your code must comply with the CS 190 Style Specifications, and work on the ECF machines. The marking scheme for Assignment 2 is available here.

Part Zero: Setup

Like the last assignment, you'll be submitting code via SVN.

You will need a partner for this assignment (which includes labs 3 and 4). Your partner must be from the same lab group as yourself. NOTE: lab groups assignments have changed slightly, to balance the student-TA ratios in the lab. You may work with the same person you did for Assignment 1 provided they are in your lab group.

The curent lab group assignments are posted on Piazza, along with a page listing who has partnered with who.

Like the last assignment, you and your partner will have to create a group on MarkUs so you may checkout the SVN repository for this assignment.

Part One: A Linked List of Passengers

Begin by downloading the files ttc.h, passenger.c and test_passenger.c. Add the files to your svn repository for a2 (will look like group_0000/a2/).

The file ttc.h contains a struct passenger, which we will use to make linked lists of people waiting for trains. Each passenger has a value waiting, the number of minutes they have been waiting for their train.

The file passenger.c is the file that you will be writing code in. You are to implement the following functions:

  1. struct passenger* make_passenger() -- this creates a new node of the linked list using malloc, and sets its waiting time to 0, and node->next to NULL. It returns a pointer to the new node.
  2. void print_passenger(struct passenger *node) -- this prints the waiting time of a single passenger. print_passenger(NULL) should print "NULL".
  3. void insert_passenger_after(struct passenger *node, struct passenger *new_node) -- this inserts a new passenger, new_node, into the linked list, directly after the node "node". Assert that neither node nor new_node are NULL.
  4. void print_passenger_list(struct passenger *first) -- this prints the waiting times of every passenger in the linked list, beginning with first. Before printing waiting times, it should print "Waiting times: \n" to make things more clear when testing your code.
  5. void increment_passenger_list(struct passenger *first) -- this increments each passenger's waiting time by one minute.
  6. int num_passengers(struct passenger *first) -- this returns the total number of passengers in a linked list. If first is null, the total should be 0.
  7. double average_passenger_list(struct passenger *first) -- returns the average waiting time of the passengers in the linked list starting with first. average_passenger_list(NULL) should return -1.
  8. void remove_first_passenger(struct passenger **node) -- removes the first node of the linked list, setting *node to now point to what was the second node -- this preserves the rest of the linked list and frees the memory of the removed node. Assert that *node != NULL.
  9. void clear_passenger_list(struct passenger **first) -- this removes all elements from the linked list that *first points to, freeing their memory. The actual node associated with first (**first) should be freed -- and the pointer to it (*first) set to NULL. Note that this takes in a pointer to a pointer!

The file test_passenger.c contains test cases for all of these methods. Comment/uncoment the lines in this file to test your code as you go.

To compile, use: gcc -Wall ttc.h passenger.c test_passenger.c -o passenger

If that gets tedious after a while, you can alternatively download this file, Makefile (no filename extension) to the same directory as your code. To compile, type make passenger. We'll be talking about Makefiles later this term -- this is just a little preview of them. :)

Your TAs will be checking whether your code compiles with no warnings from -Wall!

Part Two: A Linked List of Trains

For our next step, we will make a linked list of trains. Download the files train.c and test_train.c. Add the files to your svn repository for a2 (will look like group_0000/a2/).

For our struct train, a train has a position on the track (a nonnegative integer) and a unique id number.

Your task is to implement the following methods in train.c:

  1. struct train* make_train(int iden, int position) -- this creates a new node of the linked list using malloc, and sets node->next to NULL. It returns a pointer to the new node.
  2. int contains_train_id(struct train *first, int value) -- this returns 1 if any train in the linked list pointed to by first has the id number == value. Otherwise this returns 0. The argument *first refers to the first train in the linked list.
  3. void prepend_train(struct train **first, struct train *new_node) -- this inserts a new train, new_node, at the front of the linked list. The value of *first should be new_node by the end of the method. Assert that nether *first nor new_node are NULL. Trains should also be in order on the track, and not occupy the same position: assert that new_node's position is strictly smaller than the positions of any other trains in the list. Also assert that no train on the track has the same id number as new_node (contains_train_id returns 0).
  4. void print_trains(struct train *first) -- this should print each train in the linked list using the method print_train (provided to you). It should start by printing "---------- The trains ---------- \n".
  5. int can_advance(struct train *current, int passengers_on_platform) -- returns whether a train can safely advance. For a train to advance, the next train on the track must be more than one position unit ahead on the track, and there must be no passengers on the platform. Assert that the number of passengers on the platform is nonnegative, and that current != NULL.
  6. void advance_train(struct train *current, int passengers_on_platform) -- increases a train's position if and only if the train can advance
  7. int num_trains(struct train *first) -- returns the number of trains in the linked list. Return 0 if first is NULL.
  8. double avg_train_dist(struct train *first) -- returns the average distance between trains. Returns 0 if first is NULL. Assumes a train is 1 km long.
  9. void remove_train_after(struct train *node) -- removes the node directly after "node" -- this preserves the rest of the linked list and frees the memory of the removed node. Assert that node is not NULL.
  10. void clear_all_trains(struct train **first) -- this removes all elements from the linked list that *first points to, freeing their memory. The actual node associated with first (**first) should be freed -- and the pointer to it (*first) set to NULL. Note that this takes in a pointer to a pointer!

To compile, use: gcc -Wall ttc.h train.c test_train.c -o train

If you're using the Makefile, you can compile with make train

Test your code incrementally with test_train.c.

Ensure that you commit your code by the end of the lab session.

Waiting to Talk to Your TA?

Get started on Lab 4!