Fair and Swift Ticket Allocation

Application Overview

In many areas of life, we provide goods and services to people ordered by when they line up for access (e.g., grocery store checkouts, TSA security lines). While this might promote one notion of fairness by avoiding “cutting in line” (as we will explore soon with the queue data structure), it can also result in inequalities in some applications, especially when people might make multiple purchases at once.

Imagine that you want to order tickets to your favorite popular musical artist who will be performing soon at a nearby, large concert venue. Tickets sales will begin promptly early in the morning. You (and many others) might want to buy multiple tickets, so you “get in line” by logging into the ticket sellers website. Due to popularity, many people log in simultaneously right when ticket sales open up, and you find yourself #10,578 in the line. That’s close enough to the front that you will hopefully get tickets, so long as those who logged in milliseconds before you do not buy too many tickets each. However, you will likely be stuck purchasing tickets that are for seats far from the stage where it is difficult to see your favorite artist. It would be natural to ask whether it is really fair that others who logged in simultaneously but won the electronic speed lottery should get all the good seats?

An alternative approach that might be more fair would be to keep the same line ordering, but:

  1. Each person can only buy one ticket at a time until all others have a chance to buy a ticket, then
  2. Each person can buy a second ticket in reverse order so that those who purchased a first ticket later get to buy a second ticket earlier, then
  3. Each person can buy a third ticket (if desired) in the original order, then
  4. Each person can buy a fourth ticket (if desired) in reverse order, etc. until all tickets have been sold

In this lab, we will use the doubly-linked list and its iterator to simulate this ticket allocation process to see whether it might be more fair than the traditional approach. Here, we consider the approach to be “fair” if the sum of everyone’s ticket numbers (starting with 1) are the same (so that one person doesn’t have a total ticket allocation that is much more favorable than anyone else, like purchasing all the front row tickets).
As an example, if we consider a scenario with 5 people trying to purchase 20 tickets, we should see the following ticket allocation, where each person has the same sum of ticket numbers (42):

Person 1:
Ticket 1
Ticket 10
Ticket 11
Ticket 20
Sum of tickets: 42


Person 2:
Ticket 2
Ticket 9
Ticket 12
Ticket 19
Sum of tickets: 42


Person 3:
Ticket 3
Ticket 8
Ticket 13
Ticket 18
Sum of tickets: 42


Person 4:
Ticket 4
Ticket 7
Ticket 14
Ticket 17
Sum of tickets: 42


Person 5:
Ticket 5
Ticket 6
Ticket 15
Ticket 16
Sum of tickets: 42

Application Instructions

You should implement your program in a class called FairTickets (in a .java file of the same name). The program should:

  1. Take the number of people and total number of tickets as two command line arguments. The total number of tickets should be a multiple of two times the number of people. Print out an error message and close the program if fewer than two command line arguments are given or the total number of tickets is not a multiple of two times the number of people.
  2. Create a MyLinkedList<String> that contains the “names” of the people trying to purchase tickets (simply named “Person 1”, “Person 2”, up to “Person n” where n is the number of people in the command line argument.)
  3. Create a MyLinkedList<MyLinkedList<Integer>> that contains a list of ticket numbers for each person (where the first inner list is the list of tickets for the first person, etc.). You will need to use a loop to add each of the inner lists.
  4. Assign all of the tickets to each person by first iterating forward through the order of people (e.g., assigning tickets 1-5 to people 1-5) then backwards through the order of people (e.g., assigning tickets 6-10 to people 5-1). This process should continue (iterating forward then backwards through the people) until all tickets are assigned.
  5. Finally print out the name of each person, their assigned tickets, and the total sum of their ticket numbers, as in the example output above.

The main flow of your program should go in a public static void main(String[] args) method, but you should use good object-oriented design to split the parts of your program into instance variables and private methods.

To earn full credit for this program, you should:

  1. Use your own MyLinkedList data structure to save both the names of people and their assigned ticket numbers
  2. Only use a ListIterator to iterate through the names and ticket lists (i.e., not use any numeric indices with the get method) so the program can be as swift as possible (e.g., maybe we have 100,000 tickets to allocate for concerts at a large football stadium).

However, if you were not able to complete the earlier parts of the lab, you can still earn partial credit by using Java’s built-in LinkedList collection and/or numeric indices with the get method.

Hint

To avoid using numeric indices to retrieve data from our data structure, we can instead use the next and previous methods from our ListIterator. And we can loop forward or backwards over our data structures using a while loop and the hastNext and hasPrevious methods like at the end of Part 3 of the Warmup.

We can also iterate through both the names and ticket collections together by creating an iterator for both linked lists, then calling next or previous on both in successive lines of code like:

// create the iterators
ListIterator<String> namesIterator = names.listIterator();
ListIterator<MyLinkedList<Integer>> ticketsIterator = allTickets.listIterator();

// get the first items from both collections
String name = namesIterator.next();
MyLinkedList<Integer> namesTickets = ticketsIterator.next();

where names is the collection created in Step 2 above and allTickets is the collection created in Step 3 above.

Committing Your Progress

Don’t forget to frequently save your progress periodically to GitHub using the add, commit, and push commands with git.