INTRODUCTION |
Nowadays, reserving seats on planes and at concert halls is done almost exclusively through online booking systems. The information is managed by online databases. Database specialists with great programming skills are responsible for the development of these systems. |
RESERVATION SYSTEM PART 1: USER INTERFACE |
An attractive user interface is used to present the reservation system to the user. A user interface can be generated with a standalone program or as a web site. It is typical that the outline of the room or the aircraft is shown where the seat layout is displayed. Seats that are already reserved will be marked with a special color, for example the free seats could be green and the already reserved seats could be red. The user can select a seating option by clicking on an empty seat. The seat then changes color, let's say to yellow. This selection is not yet transferred to the database server because often the user wants to reserve multiple seats at one time. The booking process is carried out only once they click the confirm button. The game library JGameGrid is ideal for implementing the graphical user interface because the seats are usually arranged in a grid-like structure. The sprite identifier (0, 1, 2) can be used to save the current states (available, option, reserved).
You have already implemented a fully functional user interface with this short program. It is of course still missing a connecting to the database [more... If you do not understand something, look at the examples in the chapter on OOP & Games] . from gamegrid import * def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): setStatusText("View refreshed") def confirm(): for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: seats[seatNb - 1].show(2) refresh() setStatusText("Reservation successful") def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation") setStatusText("Please select free seats and press 'Confirm'") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show()
|
MEMO |
The conversion of seat numbers to locations and vice versa is done in two transformation functions. The names of such mapping functions are often prefixed with to. |
RESERVATION SYSTEM PART 2: CONNECTING TO THE DATABASE |
Online databases are multi-user systems. Because many clients manipulate the data at the same time, serious access conflicts can occur depending on the situation. It is in the nature of such problems to occur only sporadically, and they are therefore difficult to master. The following scenario describes a typical conflict case: A and B can select the chosen seats as an option with a mouse click. The opted seats are then colored yellow. However, these options are not sent to the database since the customer might still want to change something or add more options. Only after some time, the faster determined customer A clicks on the confirm button to make their choice final. The database puts the seats in the state reserved (booked = 'Y'). However, customer B does not realize these changes, since the database cannot directly give feedback to customer B, and customer A is of course not in direct contact with B [more... In a client-server environment, the server can not send messages to the client by itself]. After a certain amount of time, customer B also decides and presses the confirm button.
Note: The execution of this program requires you to restart the database server, create the table reservation, and the table must be filled with initialization data (see previous chapter). from dbapi import * from gamegrid import * serverURL = "derbyserver:localhost" #serverURL = "derbyserver:10.1.1.123" dbname = "casino" username = "admin" password = "solar" tbl = "reservation" def toLoc(seat): i = ((seat - 1) % 6) + 1 k = ((seat - 1) // 6) + 2 return Location(i, k) def toSeatNb(loc): if loc.x < 1 or loc.x > 6 or loc.y < 2 or loc.y > 6: return None i = loc.x - 1 k = loc.y - 2 seatNb = k * 6 + i + 1 return seatNb def pressCallback(e): loc = toLocation(e.getX(), e.getY()) seatNb = toSeatNb(loc) if seatNb == None: return seatActor = seats[seatNb - 1] if seatActor.getIdVisible() == 0: # free seatActor.show(1) # option refresh() elif seatActor.getIdVisible() == 1: # option seatActor.show(0) # free refresh() class MyButton(GGButton, GGButtonListener): def __init__(self, imagePath): GGButton.__init__(self, imagePath) self.addButtonListener(self) def buttonClicked(self, button): if button == confirmBtn: confirm() if button == renewBtn: renew() def buttonPressed(self, button): pass def buttonReleased(self, button): pass def renew(): with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() sql = "SELECT * FROM " + tbl cursor.execute(sql) con.commit() result = cursor.fetchall() for record in result: seatNb = record[0] isBooked = (record[1] != 'N') if isBooked: seats[seatNb - 1].show(2) else: seats[seatNb - 1].show(0) refresh() setStatusText("View refreshed") def confirm(): # check if seats is still available with connect(serverURL, dbname, username, password) as con: cursor = con.cursor() for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "SELECT * FROM " + tbl + " WHERE seat=" + str(seatNb) cursor.execute(sql) result = cursor.fetchall() for record in result: if record[1] == 'Y': setStatusText("One of the seats are already taken.") return isReserved = False for seatNb in range(1, 31): if seats[seatNb - 1].getIdVisible() == 1: sql = "UPDATE " + tbl + " SET booked='Y' WHERE seat=" + \ str(seatNb) cursor.execute(sql) isReserved = True con.commit() renew() if isReserved: setStatusText("Reservation successful") else: setStatusText("Nothing to do") makeGameGrid(8, 8, 40, None, "sprites/stage.gif", False, mousePressed = pressCallback) addStatusBar(30) setTitle("Seat Reservation - Loading...") confirmBtn = MyButton("sprites/btn_confirm.gif") renewBtn = MyButton("sprites/btn_renew.gif") addActor(confirmBtn, Location(1, 7)) addActor(renewBtn, Location(6, 7)) seats = [] for seatNb in range(1, 31): seatLoc = toLoc(seatNb) seatActor = Actor("sprites/seat.gif", 3) seats.append(seatActor) addActor(seatActor, seatLoc) addActor(TextActor(str(seatNb)), seatLoc) show() renew() setTitle("Seat Reservation - Ready") setStatusText("Select free seats and press 'Confirm'") while not isDisposed(): delay(100)
|
MEMO |
You can test the reservation system with multiple user windows by repeatedly starting the TigerJython IDE on your computer and executing the same program. If all seats are reserved, you drop the table as shown in the last chapter and create/initialize it again. |
EXERCISES |
|