Untitled
unknown
python
a year ago
22 kB
19
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, bookings, trainsSeats, fareList):
refresh()
print(tabulate([["Train Schedules"]], tablefmt="rounded_grid"))
print()
# draw the view train schedules out
print(updateTable(trains))
cont = input("Enter 2 to proceed to book tickets or 0 to exit >> ")
if cont == "2":
bookTickets(trains, bookings, trainsSeats, fareList)
elif cont == "0":
return
else:
return
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":
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
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":
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
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.")
cont = input("Enter '2' to View Bookings or any key to Main Menu >> ")
if cont == "2":
os.system("cls")
viewBookings(bookings, trains, fareList, trainsSeats)
else:
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, trainsSeats):
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)
cont = input("Enter 4 to proceed to cancel tickets or 0 to exit >> ")
if cont == "4":
cancelTickets(bookings, trains, trainsSeats, fareList)
elif cont == "0":
input("\nPress any key to Main Menu >> ")
else:
print("Invalid input. Please try again.")
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, bookings, trainsSeats, fareList)
elif choice == "2":
os.system("cls")
bookTickets(trains, bookings, trainsSeats, fareList)
elif choice == "3":
os.system("cls")
viewBookings(bookings, trains, fareList, trainsSeats)
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