Project: Booking Conflict Detector
Detect overlapping bookings with a half-open time rule and return conflict pairs in input order.
Example check: Worked and guided code samples are checked against CPython 3.13. Practice uses Pyodide 0.29.5 (Python 3.13) in your browser. How we check lessons
Video lesson: Project: Booking Conflict Detector
The preview is stored on this site. YouTube loads only when you press Play. Watch on YouTube
Jump to a chapter
Read the video transcript
Select a timestamp to watch that moment on YouTube.
- 00:00
Two bookings can share one room when the first ends at the exact moment the next begins. A booking from nine to ten and another from ten to eleven should not be called a conflict. That sounds obvious on a calendar, yet one less-than-or-equal sign in code can report the handoff as an overlap. In this project we will build a conflict detector for a small list of bookings. Each record has a unique name, a start minute, and an end minute measured after midnight. This keeps the interval rule visible without adding date parsing or time zones before we need them. We will first run the incorrect inclusive comparison and observe a false conflict.
- 00:41
Then we will derive the two strict comparisons that detect partial overlap and full containment while allowing touching endpoints. Finally we will validate records and return conflict name pairs in a predictable order. The PythonLessonLab project page includes solved examples and a checked task. A real reservation service needs rooms, dates, recurring bookings, and simultaneous edits; this focused exercise addresses one well-defined interval question you can test thoroughly. The loop examines each unordered pair once, following the input order. A with B is first, A with C is second, and B with C is third.
- 01:23
The first pair is wrong. A ends at minute six hundred, and B starts at minute six hundred. There is no minute during which both occupy the room. The condition uses less-than-or-equal on both sides, so equality at one boundary counts as overlap. C really conflicts with both: it starts before A ends, and B starts before C ends. We want exactly those two pairs. It helps to say the time convention aloud before editing the code. We will treat each booking as a half-open interval: the start minute is included and the end minute is excluded. With that convention, one booking may end at the same point another begins.
- 02:03
A different business rule could require a cleaning gap between bookings, but then we would model that gap explicitly. We should not accidentally create it by choosing the wrong comparison operator. The first condition says the start of A must be before the end of B. The second says the start of B must be before the end of A. Both have to hold. For the touching pair, B starts exactly when A ends, so the second strict inequality is false. For the containment pair, the small interval lies entirely inside the large one, and both inequalities are true. A shortcut that only checks whether B's start lies inside A can miss the reverse
- 02:44
containment case when B surrounds A. The symmetric two-sided condition handles both directions and partial overlaps. Notice that this function only compares well-formed intervals. If the start equals the end, or if a time is outside one day, the condition has no useful business meaning. We should validate all records before producing a result. Validation also lets us reject duplicate names, because a pair of identical names would make the returned report ambiguous. The overlap formula is short; the rest of a reliable solution is an explicit input contract and a deterministic output order.
- 03:26
The first loop validates every record before a conflict report is built. Each booking has three fields, a nonblank unique name, and ordinary integer minutes from zero through 1440 with a positive duration. We use exact int checks because booleans are integer subclasses in Python but do not make sense as minutes here. We strip names when checking uniqueness, so A and space-A-space cannot slip through as two supposedly different labels. The second nested loop compares each record with later records only. That avoids duplicate reversed pairs and makes the report order follow the input- pair order.
- 04:07
The strict overlap condition removes the false A-B conflict while preserving A-C and B-C. The function does not change any booking tuple. This is intentionally a small in-memory detector with quadratic comparisons, which is fine for a teaching set and makes the rule transparent. A large reservation service would need indexing, room separation, and careful concurrency handling. For now, correct boundaries and understandable output matter more than premature optimization. Empty input returns an empty report. Two bookings that touch at minute sixty also return no conflict, because neither occupies that instant together under our half-open rule.
- 04:51
The containment example confirms we did not fix the boundary bug by narrowing the test too much. Finally, a zero-length booking and a boolean minute value both raise ValueError before a report is returned. You can extend this set with reversed times, a duplicate name, or a value beyond minute 1440. Each case should follow the contract we stated before coding. In the browser project, the starter code uses the wrong inclusive comparison, so the prepared output contains an extra pair. Fix the rule, validate records, and let the task checker challenge touching, containment, and invalid inputs.
- 05:31
After passing, try drawing each interval as a segment on paper and predicting the pairs before running code. That habit is useful whenever comparison operators encode a real-world boundary. The key result is not just two correct pairs; it is a rule that another developer can explain, test, and change deliberately if the reservation policy later adds a required gap.
Understand the concept
Two bookings can share a room only when their occupied time intervals do not overlap. This project models each booking as (name, start, end), where times are integer minutes after midnight. We choose half-open intervals [start, end): the start belongs to a booking, but its end does not. A booking from 09:00 to 10:00 can therefore be followed immediately by one starting at 10:00 without conflict.
For intervals A and B, overlap occurs when A.start < B.end and B.start < A.end. The strict less-than signs encode the touching-boundary rule. Using <= would call the 10:00 handoff a collision. A condition based only on whether one start lies inside the other booking can also miss containment cases, where one interval surrounds another. The two-sided test handles both partial and full overlap.
The result lists name pairs in deterministic input-pair order: compare the first booking with every later booking, then the second with later bookings, and so on. Validate every booking before comparing: name must be unique and nonblank; start and end must be non-Boolean integers satisfying 0 <= start < end <= 1440. A zero-duration or reversed booking is invalid, not a conflict. The function never mutates the input.
The checked project includes touching boundaries, partial overlap, one booking contained inside another, empty input, and invalid times. It uses minutes rather than parsing time strings so the central interval rule is visible. A real reservation system would also consider dates, time zones, rooms, recurrence, and cancellation. Those are deliberately outside this small, testable contract.
- Half-open intervals let endpoints touch
- Overlap needs two strict inequalities
- Containment is still overlap
- Pair iteration order is deterministic
See it step by step
Read the code, predict the output, then compare it with the result.
01. Touch at the exact handoff
a = (540, 600)
b = (600, 660)
print(a[0] < b[1] and b[0] < a[1])
print(a[0] <= b[1] and b[0] <= a[1])False
TrueStrict comparison implements half-open intervals; <= invents a conflict at the handoff.
02. Detect full containment
outer = (10, 90)
inner = (20, 30)
print(outer[0] < inner[1] and inner[0] < outer[1])TrueThe two-sided inequality detects a booking entirely inside another.
03. Preserve input-pair order
items = [('A',540,600),('B',600,660),('C',570,630)]
pairs = [(x[0], y[0]) for i,x in enumerate(items) for y in items[i+1:] if x[1] < y[2] and y[1] < x[2]]
print(pairs)[('A', 'C'), ('B', 'C')]Every unordered pair is inspected once, in the source order.
A closer look
Follow the reasoning, inspect each result, then try the suggested changes in the console below.
Expose a false conflict at a handoff
A room is booked from 09:00 to 10:00 and again from 10:00 to 11:00. These appointments touch at one endpoint but do not occupy the room at the same time. An overlap test with less-than-or-equal comparisons treats that shared boundary as a collision. The output below reproduces the false positive.
Choose a half-open interval model: a booking includes its start and excludes its end. That means [540,600) followed by [600,660) is allowed. The precise representation matters because an off-by-one comparison can affect every back-to-back reservation. It is better to decide the model before writing the condition.
first=(540,600)
second=(600,660)
print(first[0]<=second[1] and second[0]<=first[1])
print(first[0]<second[1] and second[0]<first[1])True
False- Inclusive inequalities report a false overlap.
- Strict inequalities implement the half-open rule.
- A handoff at the same minute is non-overlapping.
Check partial overlap and containment
A conflict is not limited to bookings that start at the same time. One can begin before another ends, or a short appointment can sit entirely inside a longer one. The symmetric overlap rule asks whether each start occurs before the other's end. If either comparison fails, the intervals do not share occupied time.
Run three pairs: a touching pair, a partially overlapping pair, and a containment pair. The latter is where one-sided checks often fail. The project compares each unordered pair only once, in input order. For a large booking set, a specialized interval algorithm could be faster, but this small exercise prioritizes transparent behavior.
def overlaps(a,b):
return a[0]<b[1] and b[0]<a[1]
print(overlaps((0,60),(60,90)))
print(overlaps((0,60),(50,90)))
print(overlaps((10,90),(20,30)))False
True
True- Touching endpoints do not overlap.
- A shared ten-minute span does.
- Full containment also satisfies the two-sided rule.
Validate bookings and report pairs
Before comparing intervals, check each record's name and minutes. Names must be nonblank and unique, starts and ends must be actual integers rather than booleans, and every interval must have positive duration inside one day. A reversed or zero-length booking is invalid input rather than a conflict result.
The completed function then visits pairs in deterministic input order. It appends names, not raw tuple objects, to make the report readable. The prepared sample contains one touching pair and two genuine overlaps. Additional task checks include empty input and invalid records, so changing only <= to < in the starter is not enough.
def find_conflicts(bookings):
seen=set()
for item in bookings:
try: name,start,end=item
except (TypeError,ValueError): raise ValueError('invalid booking')
if not isinstance(name,str) or not name.strip() or name.strip() in seen or any(not isinstance(v,int) or isinstance(v,bool) for v in (start,end)) or not 0<=start<end<=1440:
raise ValueError('invalid booking')
seen.add(name.strip())
result=[]
for i,first in enumerate(bookings):
for second in bookings[i+1:]:
if first[1]<second[2] and second[1]<first[2]:
result.append((first[0],second[0]))
return result
print(find_conflicts([('A',540,600),('B',600,660),('C',570,630)]))[('A', 'C'), ('B', 'C')]- Reject invalid names and times first.
- Compare each pair once.
- Return only actual overlaps in stable order.
Try it in Python
Edit the example and run it. Python starts in your browser the first time you click Run.
Python console
Ready to runNeed input()? Add one value per line
Your output appears here.
Need a hint?
Validate all bookings before nested pair loops. For each pair use first_start < second_end and second_start < first_end; the strict signs make touching endpoints non-overlapping.
Complete the task and select Check task to verify your code.
Quick quiz
Three questions. You can change your answers and try again.
Typical mistakes
Everyone meets these errors. See what causes them and how to fix them.
Using inclusive endpoints
a_start <= b_end and b_start <= a_enda_start < b_end and b_start < a_endWhat happens: Back-to-back bookings are reported as a conflict.
Strict comparisons match half-open occupancy intervals.
Checking only whether a start is inside another interval
a_start <= b_start < a_enda_start < b_end and b_start < a_endWhat happens: The case where B fully contains A can be missed.
The symmetric condition covers containment and partial overlap.
Explore the runnable code
The GitHub project includes setup instructions and source code you can run on your computer. Use this lesson for the guided examples, browser task, and quiz.