2

I have a Java code for booking movie tickets. In this program, each person can only buy two tickets, a maximum of 10 tickets are sold and at the end it displays a list with the names of the people. I did the whole process where I initialized with ArrayList and storing each name within that list, but I have no idea how to make this program check within the list itself if a person has already purchased more than two tickets.

  • The program should start with an empty list and a maximum of 10 tickets available.

  • At each iteration, ask the user if they want to buy a ticket.

  • If the user wants to buy, ask for their name and add them to the list if there are still tickets available.

  • If the tickets are sold out, display a sold out message.

  • At the end, display the list of all people who bought tickets.

Here's the code:

public class BookingTickets{ public static void main(String[] args) { Scanner sc = new Scanner(System.in); ArrayList<String> list = new ArrayList<>(); int ticketsPurchased = 0; int allTickets = 10; System.out.print("Do you want to buy a ticket? (y/n): "); String response = sc.next().toLowerCase(); if (response.equals("n")) { System.out.println("Thank you. See you next time."); } while (response.equals("y")) { if (ticketsPurchased <= 2) { if (allTickets == 0) { System.out.print("Sorry, we have no more tickets!\n"); System.out.println(list); } System.out.print("How many tickets do you want to buy? "); ticketsPurchased = sc.nextInt(); System.out.print("Enter the buyer's name: "); String name = sc.next(); list.add(name); allTickets -= ticketsPurchased; } else { System.out.print("Limit of 2 tickets per person."); } System.out.print("Do you want to buy a ticket? (y/n): "); response = sc.next().toLowerCase(); } System.out.println(list); sc.close(); } } 
1
  • 1
    You could model classes Buyer and Ticket and maintain a Map<Buyer, Ticket>. Also start with List<Ticket> and subtract from it Commented Feb 13 at 23:02

3 Answers 3

4

The Methode Collections.frequency(list, name) counts the number of entries with name in the list.

It is provided by the utility class java.util.Collections.


Besides that your code has other issues and several possible improvements.

Issues:

  • Where and how you check the number of tickets per buyer with if (ticketsPurchased <= 2) is wrong. You can only count the already bought tickets, after the buyer name is entered - and then first count the occurences in the list and if it is lower(!) than 2 let the purchase happen.
  • When you are out of tickets in general, you should leave the loop and no longer ask the user to buy a ticket or not. Right now you just output a "sorry..." but then continue with the purchase as if there were more tickets available.

Improvements:

  • Declare list only as List<String>. Which implementation of List you actually use doesn't matter for the rest of the code and this way it is easier to swap for other implementations of List if you need to or want to try it out. (List<String> list = new ArrayList<>();)
  • You can output the message "Thank you. See you next time." simply after the loop, you don't need to put it into an if.
  • You don't have to count the tickets already sold or the tickets still available. Simply count the entries of the list and extend the loop condition so it has to be < 10 to enter the loop. (In the loop, the 10th purchase will happen, this is why you just compare for < 10).
Sign up to request clarification or add additional context in comments.

Comments

2

The Answer by cyberbrain is correct, and smart.

Just for fun, here is a rewrite of your app to be more object-oriented. While this may be too much for a beginning student, this is the direction to head for in your learning.

Notice the separation of concerns. We create a separate class to handle each area of your app:

  • "business" domain objects (Event & Sale)
  • user-interface (TerminalUserInterface)
  • execution-lifecycle (App)

Event & Sale — domain

The Event & Sale classes represent the core of your app, the domain, what your stakeholders really care about when building your software.

These contain data (list of sales, count of tickets remaining) as well as the code that operates upon this data (adding to list of sales, decrementing count of tickets remaining).

Importantly, we could go on to write tests that exercise these classes, before bothering with any user-interface.

package work.basil.example.tickets; public record Sale( String customer , int countTicketsPurchased ) { public Sale { if ( this.countTicketsPurchased ( ) < 0 ) { throw new IllegalArgumentException ( "count tickets purchased cannot be negative" ); } } } 
package work.basil.example.tickets; import java.util.ArrayList; import java.util.List; public class Event { public final String name; private final int totalCountTickets; private int remainingTicketCount; private final List < Sale > sales; public final int MAXIMUM_TICKETS_PER_PURCHASE = 2; public Event ( final String name , final int countTicketsToBeSold ) { // Arguments this.name = name; this.totalCountTickets = countTicketsToBeSold; this.remainingTicketCount = this.totalCountTickets; // Other initialization. this.sales = new ArrayList < Sale > ( ); } // Getters public boolean ticketsAvailable ( ) { return remainingTicketCount > 0; } public int countRemainingTickets ( ) { return remainingTicketCount; } // Logic public void addSale ( final Sale theSale ) { if ( theSale.countTicketsPurchased ( ) > MAXIMUM_TICKETS_PER_PURCHASE ) { throw new IllegalArgumentException ( "Too many tickets in purchase requested. Limit:" + MAXIMUM_TICKETS_PER_PURCHASE ); } this.remainingTicketCount = this.remainingTicketCount - theSale.countTicketsPurchased ( ); // Decrement tickets available. this.sales.add ( theSale ); } public String salesReport ( ) { StringBuilder salesReport = new StringBuilder ( ); this.sales.forEach ( salesReport :: append ); return salesReport.toString ( ); } // `Object` Overrides @Override public String toString ( ) { return "Event{" + "name='" + name + '\'' + ", remainingTicketCount=" + remainingTicketCount + ", sales.size()=" + sales.size ( ) + ", MAXIMUM_TICKETS_PER_PURCHASE=" + MAXIMUM_TICKETS_PER_PURCHASE + '}'; } } 

TerminalUserInterface — user interface

We move all the code for interacting with the user on the console to this one class. We can focus on that user interaction without thinking about the domain implementation details contained in a separate class.

Notice the use of a helper method makePurchase to break up the code into more manageable chunks. (In the old days, we called that a subroutine.)

package work.basil.example.tickets; import java.time.Instant; import java.util.Objects; import java.util.Scanner; public class TerminalUserInterface { private final Event event; public TerminalUserInterface ( final Event theEvent ) { this.event = Objects.requireNonNull ( theEvent ); } public void run ( ) { final Scanner scanner = new Scanner ( System.in ); while ( event.ticketsAvailable ( ) ) { System.out.println ( "------| Event: " + event.name + " |------" ); if ( ! this.event.ticketsAvailable ( ) ) { System.out.println ( "Event sold out.-" ); break; } System.out.println ( "TICKETS AVAILABLE: " + event.ticketsAvailable ( ) + " … " + this.event.countRemainingTickets ( ) ); System.out.println ( "Make purchase: (y/n): " ); String response = scanner.next ( ).toLowerCase ( ); switch ( response.toLowerCase ( ) ) { case "n" -> { System.out.println ( "Exiting app, per your request." ); return; } case "y" -> { this.makePurchase ( scanner ); } default -> { System.out.println ( "Invalid input." ); return; } } } System.out.println ( "App exiting." + Instant.now ( ) ); } private void makePurchase ( final Scanner scanner ) { // Customer name System.out.println ( "Customer name: " ); String name = scanner.next ( ); if ( name.isBlank ( ) ) { System.out.println ( "Customer name is blank." ); return; } // Count tickets to purchase System.out.println ( "How many tickets to purchase?: " ); int countTicketsToPurchase = scanner.nextInt ( ); // Too few tickets. if ( countTicketsToPurchase <= 0 ) { System.out.println ( "Count of tickets must be a positive integer. Your input: " + countTicketsToPurchase ); return; } // Too many tickets. if ( countTicketsToPurchase > this.event.MAXIMUM_TICKETS_PER_PURCHASE ) { System.out.println ( "Count of tickets limited to: " + this.event.MAXIMUM_TICKETS_PER_PURCHASE + ". Your input: " + countTicketsToPurchase ); return; } Sale sale = new Sale ( name , countTicketsToPurchase ); this.event.addSale ( sale ); System.out.println ( "Purchase executed successfully: " + sale.toString ( ) ); } } 

App — execution lifecycle (setup-teardown)

Notice how we set up the needed objects, in this case an Event object, before starting the user-interface.

package work.basil.example.tickets; import java.time.Instant; public class App { public static void main ( String[] args ) { App app = new App ( ); app.demo ( ); } private void demo ( ) { System.out.println ( "INFO - Demo start. " + Instant.now ( ) ); // Setup Event event = new Event ( "Flea Circus" , 12 ); // User-interface TerminalUserInterface tui = new TerminalUserInterface ( event ); tui.run ( ); // Teardown System.out.println ( "DEBUG - event = " + event ); System.out.println ( "INFO - Demo done. " + Instant.now ( ) ); } } 

Example run

INFO - Demo start. 2025-02-15T00:22:17.436491Z ------| Event: Flea Circus |------ TICKETS AVAILABLE: true … 12 Make purchase: (y/n): y Customer name: Bubba How many tickets to purchase?: 2 Purchase executed successfully: Sale[customer=Bubba, countTicketsPurchased=2] ------| Event: Flea Circus |------ TICKETS AVAILABLE: true … 10 Make purchase: (y/n): y Customer name: Jean-Pierre How many tickets to purchase?: 1 Purchase executed successfully: Sale[customer=Jean-Pierre, countTicketsPurchased=1] ------| Event: Flea Circus |------ TICKETS AVAILABLE: true … 9 Make purchase: (y/n): n Exiting app, per your request. DEBUG - event = Event{name='Flea Circus', remainingTicketCount=9, sales.size()=2, MAXIMUM_TICKETS_PER_PURCHASE=2} INFO - Demo done. 2025-02-15T00:22:59.300977Z 

Comments

1

The fundamental problem you have is you are trying to use a single int (ticketsPurchased) to keep track of how many tickets all buyers have purchased. Instead, you are going to need many ints. For now, you may just want to keep a List<Integer> ticketsPurchased, where the index of each Integer maps to the name in the list of buyers with the same index.

A more sophisticated solution would be to create a User class to keep the name and tickets purchased together in a single data structure.

2 Comments

I don't think it would be a good practice to fake a Map with two lists that have to keep synced indexes. You could track the number of tickets per buyer in a Map<String, Integer> but for this simple task it seems a bit over-engineered ;-)
@cyberbrain I assumed the OP in a beginner class that hadn't covered Map yet. I wanted to give them a solution that only used the tools they had already shown they know how to use (which your answer does better).

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.