LESSON 82 · ADVANCED PROJECT37 min

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

Read the video transcript

Select a timestamp to watch that moment on YouTube.

  1. 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.

  2. 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.

  3. 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.

  4. 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

  5. 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.

  6. 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.

  7. 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.

  8. 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.

  9. 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

PYTHON
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])
EXPECTED OUTPUT
False
True

Strict comparison implements half-open intervals; <= invents a conflict at the handoff.

02. Detect full containment

PYTHON
outer = (10, 90)
inner = (20, 30)
print(outer[0] < inner[1] and inner[0] < outer[1])
EXPECTED OUTPUT
True

The two-sided inequality detects a booking entirely inside another.

03. Preserve input-pair order

PYTHON
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)
EXPECTED OUTPUT
[('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.

01 / 03

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.

PYTHON
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])
EXPECTED OUTPUT
True
False
Follow the reasoning
  1. Inclusive inequalities report a false overlap.
  2. Strict inequalities implement the half-open rule.
  3. A handoff at the same minute is non-overlapping.
02 / 03

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.

PYTHON
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)))
EXPECTED OUTPUT
False
True
True
Follow the reasoning
  1. Touching endpoints do not overlap.
  2. A shared ten-minute span does.
  3. Full containment also satisfies the two-sided rule.
03 / 03

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.

PYTHON
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)]))
EXPECTED OUTPUT
[('A', 'C'), ('B', 'C')]
Follow the reasoning
  1. Reject invalid names and times first.
  2. Compare each pair once.
  3. 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 run
Need input()? Add one value per line
Ctrl / ⌘ + Enter to run
OUTPUT
Your output appears here.
Your turnComplete find_conflicts(bookings) for (name, start, end) tuples. Validate unique nonblank names and integer minutes with 0 <= start < end <= 1440. Return overlapping name pairs in input-pair order; bookings that only touch at an endpoint must not conflict. Prepared output must be [('A', 'C'), ('B', 'C')].
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.

    01.Does [09:00,10:00) overlap [10:00,11:00)?

    02.Which test detects partial and contained overlap?

    03.What should happen for a booking with start == end?

    Typical mistakes

    Everyone meets these errors. See what causes them and how to fix them.

    Using inclusive endpoints

    COMMON MISTAKE
    a_start <= b_end and b_start <= a_end
    FIX
    a_start < b_end and b_start < a_end

    What 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

    COMMON MISTAKE
    a_start <= b_start < a_end
    FIX
    a_start < b_end and b_start < a_end

    What happens: The case where B fully contains A can be missed.
    The symmetric condition covers containment and partial overlap.

    Browse this lesson’s problem fixes

    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.

    View this project on GitHub

    Sources and further reading