Untitled
unknown
python
4 months ago
20 kB
10
Indexable
from tabulate import tabulate import os import random # global variables and constant g_destinationList = ["Perlis", "Kedah", "Penang", "Perak", "Selangor", "Negeri Sembilan", "Melaka", "Johor", "Kelantan", "Terengganu", "Pahang"] REFUNDRATE = 0.75 # generate refund policy def refundPolicy(): print(tabulate([["\nPlease note that our train ticket system does not support a full refund.\nInstead, a 75% refund of the ticket fee will be provided in the event of a cancellation.\nWe kindly request your understanding and encourage you to proceed with your bookings and cancellation at your own discretion.\nThank you for your cooperation.\n"]], tablefmt="rounded_grid")) # update the train schedule whenever we change the number of available seats def updateTable(trains): table = tabulate( trains, headers=["Train No", "Train Type", "Origin", "Destination", "Available Seat", "Fare/Pax", "Departure", "Arrival"], tablefmt="fancy_grid", numalign="right", colalign=("center", "center", "center", "center", "center", "center", "center") ) return table # converts an alphabet into its corresponding index (A -> 0, B -> 1, etc.) def alphabetToInt(alphabet): if alphabet == "A": return 0 elif alphabet == "B": return 1 elif alphabet == "C": return 2 elif alphabet == "D": return 3 elif alphabet == "E": return 4 elif alphabet == "F": return 5 elif alphabet == "G": return 6 elif alphabet == "H": return 7 else: return -1 # if the user input the alphabet is not in our seat, throw error # generate the default seats for each train def templateSeats(): seatsAbove = [ ["A01", "B01", "C01", "D01", "E01", "F01", "G01", "H01"], ["A02", "B02", "C02", "D02", "E02", "F02", "G02", "H02"] ] seatsBelow = [ ["A03", "B03", "C03", "D03", "E03", "F03", "G03", "H03"], ["A04", "B04", "C04", "D04", "E04", "F04", "G04", "H04"] ] seats = [seatsAbove, seatsBelow] return seats # clear the console with better visualization def refresh(): print("\n\n\n\n\n\n\n\n\n\n") # randomize the destination/origin def destinationRandomize(): destination = random.choice(g_destinationList) g_destinationList.remove(destination) return destination # randomize the fare in 50, 100, 150, 200 def fareRandomize(): fare = random.randint(1,4) return fare * 50 # draw the main menu here using tabulate def drawMenu(): menuChoice = [ ["(1) View Train Schedules"], ["(2) Book Tickets"], ["(3) View Bookings"], ["(4) Cancel Tickets"], ["(5) Exit Program"] ] menuTable = tabulate( menuChoice, tablefmt="fancy_grid", headers=[" Malaysia Boleh Train Service"] ) refresh() print(menuTable) # Yik Yang part def viewTrainSchedules(trains): refresh() print(tabulate([["Train Schedules"]], tablefmt="rounded_grid")) print() # draw the view train schedules out print(updateTable(trains)) input("\nPress any key to Main Menu >> ") os.system("cls") # Li Hen part def bookTickets(trains, bookings, trainsSeats, fareList): # this variable will increase by 1 everytime a ticket is successfully generated totalGeneratedTicketID = 1 while True: refresh() print(tabulate([["Available Trains to Book"]], tablefmt="rounded_grid")) print() print(updateTable(trains)) book = input("\nEnter Train Number (101, 102, 103) to view seats, or 0 to exit >> ") if book == "0": os.system("cls") return selectedTrain = None trainIndex = None # Index of the selected train # get the corresponding train index so can be easily access in later use for no in range(len(trains)): if trains[no][0] == book: selectedTrain = trains[no][0] trainIndex = no break # handle invalid input while not selectedTrain: book = input("Enter Train Number (101, 102, 103) to view seats, or 0 to exit >> ") if book == "0": os.system("cls") return selectedTrain = None trainIndex = None # Index of the selected train for no in range(len(trains)): if trains[no][0] == book: selectedTrain = trains[no][0] trainIndex = no break pax = 0 while True: pax = input("How many people? >> ") # handle invalid input if pax.isdigit() and 0 < int(pax) <= trains[trainIndex][4]: pax = int(pax) break else: print("Invalid input! The number must be between 1 and 32. Try again.") continue fare = fareList[trainIndex] * pax # get the total price of the current booking isBooked = False bookedSeats = [] # keep track of seats booked in this session while True: refresh() print(tabulate([[f"\nHere are the available seats for {trains[trainIndex][1]} Express (Train No: {selectedTrain})"]], tablefmt="rounded_grid")) print() # Draw the seats with seperately above and below seatAboveTable = tabulate( trainsSeats[trainIndex][0], tablefmt="heavy_grid" ) print(seatAboveTable) print("--> Walk way") seatBelowTable = tabulate( trainsSeats[trainIndex][1], tablefmt="heavy_grid" ) print(seatBelowTable) while pax > 0: print(f"Total pax that haven't chosen a seat: {pax}") seatChoice = input("Select a seat (e.g., A01, B04) per pax at a time, or 0 to exit >> ").upper() if seatChoice == "0": os.system("cls") return # handle invalid input while len(seatChoice) != 3 or not seatChoice[1:].isdigit(): seatChoice = input("Invalid format, select a seat (e.g., A01, B04) per pax at a time, or 0 to exit >> ").upper() if seatChoice == "0": os.system("cls") return # get the row and col from the seatChoice to easily access through corresponding seat in list row = int(seatChoice[-1]) - 1 col = alphabetToInt(seatChoice[0]) # handle invalid input while row < 0 or row >= 4 or col == -1: seatChoice = input("Invalid format, the range is in between (A-H) and (01-04) >> ").upper() if len(seatChoice) != 3 or not seatChoice[1:].isdigit(): continue row = int(seatChoice[-1]) - 1 col = alphabetToInt(seatChoice[0]) if row < 2: # if the seat is in upper row if trainsSeats[trainIndex][0][row][col] == "XXX": input("The seat is already booked. Please choose another available seat.\n") continue trainsSeats[trainIndex][0][row][col] = "XXX" else: # if the seat is in lower row if trainsSeats[trainIndex][1][row - 2][col] == "XXX": input("The seat is already booked. Please choose another available seat.\n") continue trainsSeats[trainIndex][1][row - 2][col] = "XXX" bookedSeats.append((row, col)) # store the booked seat into list pax -= 1 print(f"The seat {seatChoice} has been booked successfully.\n") isBooked = True # generate the random 3 digits number for the ticket id to look better ticketIDGenerator = random.randint(100,999) if pax == 0 and isBooked: print(f"Your total payment is: RM{fare} (RM{fareList[trainIndex]} per pax)") print() confirmation = input("Are you confirm with your booking seats? (Y/N) >> ").upper() while confirmation not in ["Y", "N", "YES", "NO"]: confirmation = input("Invalid input. Are you confirm with your booking seats? (Y/N) >> ").upper() if confirmation in ["Y", "YES"]: person = int(fare / fareList[trainIndex]) print("\nGenerating your receipt (Ticket ID)...") ticketID = f"{trains[trainIndex][1]} Express {selectedTrain} - {int(fare / fareList[trainIndex])}{ticketIDGenerator}{totalGeneratedTicketID}{trainIndex + 1}" totalGeneratedTicketID += 1 # use dict to store the confirmed booking bookings.append({"Ticket ID": ticketID, "Seats": bookedSeats}) trains[trainIndex][4] -= person print() print("Your receipt (Ticket ID) is generated successfully. Please head to 'View Bookings' to check your details.") input("Press any key to main menu >> ") return elif confirmation in ["N", "NO"]: # cancel the booking print("Booking cancelled. Reverting seat availability...") # loop through each seat in bookedSeats for seat in bookedSeats: row = seat[0] col = seat[1] # seperate the seat into row and col seatLabel = "ABCDEFGH"[col] # map column index to the corresponding letter seatLabel += "0" + str(row + 1) # check if the seat is in the upper rows (row < 2) or lower rows then restore the seat if row < 2: trainsSeats[trainIndex][0][row][col] = seatLabel else: trainsSeats[trainIndex][1][row - 2][col] = seatLabel input("Seats have been restored. Returning to the main menu. Press any key to continue >> ") os.system("cls") return # Malcolm part def viewBookings(bookings, trains, fareList): while True: refresh() # check if user haven't book any ticket if not bookings: print(tabulate([["You don't have any booking yet."]], tablefmt="rounded_grid")) input("\nPress any key to Main Menu >> ") os.system("cls") return else: print(tabulate([["These are the detail(s) about your recent booking"]], tablefmt="rounded_grid")) # loop through bookings to get all the ticket id that had booked for i in range(len(bookings)): print(f"-> ({i + 1}) {bookings[i]["Ticket ID"]}") print() while True: choice = input(f"Input 1 to {len(bookings)} to view corresponding details, or 0 to exit >> ") # handle invalid input while not choice.isdigit(): choice = input("Invalid input, try again >> ") choice = int(choice) if choice == 0: os.system("cls") return # if input out of boundary, throw exception if choice > len(bookings): continue # display the booking details if found else: os.system("cls") refresh() print(tabulate([[f"Booking Details of {bookings[choice - 1]["Ticket ID"]}"]], tablefmt="rounded_grid")) print() # get all the details so can be easily access later pax = int(bookings[choice - 1]["Ticket ID"][-7:-5]) trainNo = int(bookings[choice - 1]["Ticket ID"][-1]) - 1 payment = f"RM {fareList[trainNo] * pax:5.2f}" departure = trains[trainNo][6] arrival = trains[trainNo][7] # initialize an empty list to store formatted seat details seatDetailsList = [] # loop through each seat in the selectedBooking["Seats"] list for seat in bookings[choice - 1]["Seats"]: row = seat[0] # rol index col = seat[1] # column index seatLabel = "ABCDEFGH"[col] # get the corresponding column letter seatLabel += "0" + str(row + 1) seatDetailsList.append(seatLabel) # join the seat labels into a single string seatDetails = ", ".join(seatDetailsList) details = [ [pax, departure, arrival, payment, seatDetails] ] table = tabulate( details, headers=["Pax", "Departure Time", "Arrival Time", "Fare/Pax", "Seats"], tablefmt="fancy_grid", colalign=("center", "center", "center", "center", "center") ) print(table) input("\nPress any key to main menu >> ") os.system("cls") return # Qinyi part def cancelTickets(bookings, trains, trainsSeats, fareList): while True: refresh() print(tabulate([["Cancel Your Ticket(s) Here"]], tablefmt="rounded_grid")) cancelList = [] if not bookings: print("You haven't purchased your ticket yet.") input("Enter any key to main menu >> ") os.system("cls") return else: print() # loop the bookings list to get all the booked seats for i in range(len(bookings)): print(f"-> ({i + 1}) {bookings[0]["Ticket ID"]}") cancelList.append(i) print() while True: choice = input(f"Enter the number(1 to {len(cancelList)}) to cancel the corresponding ticket, or '0' to exit >> ") # handle invalid input while not choice.isdigit(): choice = input(f"Invalid input, enter the number in between 1 to {len(cancelList)} >> ") choice = int(choice) - 1 if choice == - 1: os.system("cls") return if choice > len(cancelList): continue if choice in cancelList: refresh() trainNo = int(bookings[choice]["Ticket ID"][-1]) - 1 pax = int(bookings[choice]["Ticket ID"][-7:-5]) payment = fareList[trainNo] * pax refundRec = [ ["The total amount of payment", f"RM{payment:5.2f}"], ["The refund rate ", f"{REFUNDRATE*100:5.2f}%"], ["The total refundable fees ", f"RM{payment * REFUNDRATE:5.2f}"] ] refundPolicy() refundTable = tabulate( refundRec, tablefmt="fancy_grid", headers=["Description", "Amount"] ) print(refundTable) while True: answer = input("Are you sure you want to cancel? (Y/N) >> ").upper() if answer in ["YES", "Y"]: print("Cancelling ticket...") trains[trainNo][4] += pax seatList = [] # retrieve the seat from the bookings list and restore back the seats for seats in bookings[i]["Seats"]: row, col = seats seatLabel = "ABCDEFGH"[col] seatLabel += "0" + str(row + 1) if row < 2: trainsSeats[trainNo][0][row][col] = seatLabel else: trainsSeats[trainNo][0][row - 2][col] = seatLabel input(f"Ticket ID {bookings[choice]["Ticket ID"]} has been cancelled successfully.") del bookings[choice] os.system("cls") break elif answer in ["NO", "N"]: os.system("cls") break else: continue break continue # main entry point of the program def main(): # declare variables here fareList = [fareRandomize(), fareRandomize(), fareRandomize()] tierList = ["Gold" , "Silver", "Platinum"] # check train tier list # less than 100 is silver, less than 150 is gold, less than 200 is platinum for i in range(len(fareList) - 1): if fareList[i] < 100: tierList[i] = "Silver" elif fareList[i] < 150: tierList[i] = "Gold" else: tierList[i] = "Platinum" trains = [ ["101", f"{tierList[0]}", f"{destinationRandomize()}", f"{destinationRandomize()}", 32, f"RM {fareList[0]}", "8.00am", "11.00am"], ["102", f"{tierList[1]}", f"{destinationRandomize()}", f"{destinationRandomize()}", 32, f"RM {fareList[1]}", "22.00pm", "23.00pm"], ["103", f"{tierList[2]}", f"{destinationRandomize()}", f"{destinationRandomize()}", 32, f"RM {fareList[2]}", "18.00pm", "20.00pm"] ] table = tabulate( trains, headers=["Train No", "Train Type", "Origin", "Destination", "Available Seat", "Fare/Pax", "Departure", "Arrival"], tablefmt="fancy_grid", numalign="right", colalign=("center", "center", "center", "center", "center", "center", "center") ) # store the trains seat for each train trainsSeats = [ templateSeats(), templateSeats(), templateSeats() ] bookings = [] # main loop while (True): drawMenu() choice = input("\nEnter your choice >> ") if choice == "1": os.system("cls") viewTrainSchedules(trains) elif choice == "2": os.system("cls") bookTickets(trains, bookings, trainsSeats, fareList) elif choice == "3": os.system("cls") viewBookings(bookings, trains, fareList) elif choice == "4": os.system("cls") cancelTickets(bookings, trains, trainsSeats, fareList) elif choice == "5": os.system("cls") refresh() print(tabulate([["Thanks for using our service, bye!"]], tablefmt="rounded_grid")) break # call the main() function main()
Editor is loading...
Leave a Comment