Sell room types per night with half-open stays, 15-minute holds, stacked pricing rules and a cancellation policy, so the hotel never oversells and back-to-back stays never clash.
Build the core of the hotel round: a service that sells room types (not room numbers) per night. Dates are whole day numbers here (day 0 is a Monday, so Friday is day % 7 == 4 and Saturday is 5), and time is a number of minutes passed in as now: nothing reads a clock.
Implement, with the lesson's names:
Stay(check_in, check_out): the half-open range of nights [check_in, check_out). nights() lists the night numbers; a check-out on or before the check-in raises ValueError (Error in JavaScript, message containing check-out).Inventory(rooms) with rooms like {"deluxe": 1}: free(room_type, stay) is the fewest rooms left on any night of the stay; take and release count a stay in or out; occupancy(room_type, night) is the share taken that night (0 to 1).apply(price, ctx) where ctx is a NightContext (given): WeekendRule (+20 percent on Friday and Saturday nights), OccupancyRule(threshold=0.75, pct=25) (+25 percent once the type is 75 percent taken that night), LongStayRule(min_nights=7, pct=10) (10 percent off a stay of 7+ nights). Whole rupees: price * (100 + pct) // 100.Pricer(base, rules) with quote(room_type, stay, inventory): one price per night, every rule applied in order.FreeUntil48h().penalty(booking, now): 0 until 48 hours before check-in at 14:00, after that the first night's price.HotelService(rooms, pricer, cancellation, hold_ttl=15):
hold(guest, room_type, stay, now) takes the nights and returns a Booking (given) with the nightly prices fixed at that moment, priced before this room is taken. Raises SoldOut when any night is full. Ids are HB0001, HB0002, ...confirm(booking_id, payment_ref, now) confirms a live hold. A retry with the same payment_ref returns the booking again. If the hold has expired, append (payment_ref, amount) to refunds and raise HoldExpired.cancel(booking_id, now) releases the nights and returns the refund: 0 for a hold, amount - penalty for a confirmed booking (also appended to refunds as (payment_ref, refund)). Cancelling a booking that is already cancelled or expired raises ValueError (Error).search(stay, now) returns {room_type: (free, total_price)} for the types with a room free on every night.hold_expires <= now and gives their nights back.JavaScript and TypeScript use camelCase (checkIn, roomType, holdTtl, holdExpires, paymentRef), search returns {deluxe: [free, total]}, and quote returns an array.
Write your code, then run 10 example tests and 4 hidden tests. Each run is limited to 8 seconds: an infinite loop gets stopped and the runtime restarts, your code stays.