Machine Coding Problem

Airport Management System

maco60macoAllinfrastructureresource-allocation-(gates)
Commonly Asked By:AmadeusSabreBoeing

Requirements & System Scope

Functional Scope (In-Scope)

  • Interval-Scheduling Gate Allocation: Models gate allocations as scheduled non-overlapping intervals, accounting for turnaround buffers.
  • Physical Aircraft Compatibility: Gate searches ensure gates match flight wingspans, jet bridge alignments, and boarding types.
  • Reactive Delay Cascades: Handles incoming flight delay propagation, shifting intervals dynamically and triggering automatic gate reassignments.
  • Resource Dispatch: Coordinates ground crew turnarounds and allocates baggage carousel belts.

Explicit Boundaries (Out-of-Scope)

  • Low-Level ATC Telemetry Sockets: Live radar socket connections or analog air-traffic communication structures are out-of-scope.
  • Global Reservation Inventory: Excludes live passenger booking, seating management, and ticket transaction processors.

Class Diagram & Entity Relationships

Class model detailing gate schedule interval booking collections:

Loading...
  • TimeInterval: Represents an absolute bound epoch millisecond range booked for a specific flight identifier.
  • Compatible Set: Fast constant-time lookup maps indicating gate structural compatibility against specific aircraft profiles.

Design Patterns & SOLID Principles

  • Observer Pattern: ATC delays trigger reactive notifications notifying check-in kiosks, visual terminal monitors, and ground teams.
  • Single Responsibility Principle (SRP): The gate service is dedicated exclusively to finding conflict-free temporal gate placements.
  • Open-Closed Principle (OCP): Turnaround strategies can be added dynamically (e.g. VIP international cleaning buffers vs budget airline buffers).

Core Execution Workflows

Gate Assignment and Delay Handling

  1. An arriving flight requests gate assignment.
  2. The system compiles flight timestamps and adds the aircraft turnaround buffer.
  3. The \`GateAssignmentService\` iterates through physical gates checking structural compatibility.
  4. For compatible gates, the system validates that the target interval has no overlap: max(start1, start2) < min(end1, end2).
  5. Upon delay signals, old slots are removed, new intervals are evaluated, and conflict cascades trigger immediate gate reassignment algorithms.

Concurrency & Thread Safety Strategy

Operating safely under concurrent flight rescheduling events:

  • Locking Intervals: Methods adding or removing slots use monitor locks or read-write locks to prevent race conditions on double-bookings.
  • Atomic Delay Updates: Delay tracking variables use synchronized modifications or volatile variables to maintain visibility across flight scheduling worker threads.

Complete Clean Code Blueprint

Clean reference designs demonstrating interval-scheduling gate assignments in Java and Python:

// โ”€โ”€โ”€ JAVA BLUEPRINT โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReentrantReadWriteLock;

enum AircraftType { SMALL, MEDIUM, LARGE }

class Flight {
    private final String flightNumber;
    private final AircraftType aircraftType;
    private final long scheduledTime;
    private final long duration;
    private long delay;

    public Flight(String flightNumber, AircraftType aircraftType, long scheduledTime, long duration) {
        this.flightNumber = flightNumber;
        this.aircraftType = aircraftType;
        this.scheduledTime = scheduledTime;
        this.duration = duration;
        this.delay = 0;
    }

    public String getFlightNumber() { return flightNumber; }
    public AircraftType getAircraftType() { return aircraftType; }
    public long getScheduledTime() { return scheduledTime; }
    public long getDuration() { return duration; }
    
    public synchronized long getDelay() { return delay; }
    public synchronized void addDelay(long delayMillis) {
        this.delay += delayMillis;
    }

    public synchronized long getActualStartTime() {
        return scheduledTime + delay;
    }

    public synchronized long getActualEndTime() {
        return scheduledTime + delay + duration;
    }
}

class TimeInterval {
    public final long start;
    public final long end;
    public final String flightNumber;

    public TimeInterval(long start, long end, String flightNumber) {
        this.start = start;
        this.end = end;
        this.flightNumber = flightNumber;
    }
}

class Gate {
    private final String id;
    private final Set<AircraftType> compatibleTypes;
    private final List<TimeInterval> schedule = new ArrayList<>();
    private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public Gate(String id, Set<AircraftType> compatibleTypes) {
        this.id = id;
        this.compatibleTypes = new HashSet<>(compatibleTypes);
    }

    public String getId() { return id; }
    
    public boolean isCompatible(AircraftType type) {
        return compatibleTypes.contains(type);
    }

    public boolean hasConflict(long start, long end) {
        lock.readLock().lock();
        try {
            for (TimeInterval interval : schedule) {
                if (Math.max(interval.start, start) < Math.min(interval.end, end)) {
                    return true;
                }
            }
            return false;
        } finally {
            lock.readLock().unlock();
        }
    }

    public void bookInterval(long start, long end, String flightNumber) {
        lock.writeLock().lock();
        try {
            schedule.add(new TimeInterval(start, end, flightNumber));
        } finally {
            lock.writeLock().unlock();
        }
    }

    public void removeInterval(String flightNumber) {
        lock.writeLock().lock();
        try {
            schedule.removeIf(ti -> ti.flightNumber.equals(flightNumber));
        } finally {
            lock.writeLock().unlock();
        }
    }

    public List<TimeInterval> getSchedule() {
        lock.readLock().lock();
        try {
            return new ArrayList<>(schedule);
        } finally {
            lock.readLock().unlock();
        }
    }
}

class GateAssignmentService {
    private final List<Gate> gates = new ArrayList<>();
    private final Map<String, Gate> flightToGateMap = new ConcurrentHashMap<>();
    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void addGate(Gate gate) {
        rwLock.writeLock().lock();
        try {
            gates.add(gate);
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public Gate assignGate(Flight flight, long turnaroundBuffer) throws Exception {
        rwLock.writeLock().lock();
        try {
            long occupationStart = flight.getActualStartTime();
            long occupationEnd = flight.getActualEndTime() + turnaroundBuffer;

            for (Gate gate : gates) {
                if (gate.isCompatible(flight.getAircraftType()) && !gate.hasConflict(occupationStart, occupationEnd)) {
                    gate.bookInterval(occupationStart, occupationEnd, flight.getFlightNumber());
                    flightToGateMap.put(flight.getFlightNumber(), gate);
                    return gate;
                }
            }
            throw new IllegalStateException("No compatible gate available for flight: " + flight.getFlightNumber());
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public void handleFlightDelay(Flight flight, long delayMillis, long turnaroundBuffer) throws Exception {
        rwLock.writeLock().lock();
        try {
            Gate gate = flightToGateMap.get(flight.getFlightNumber());
            if (gate == null) {
                throw new IllegalArgumentException("Flight " + flight.getFlightNumber() + " is not currently assigned to a gate.");
            }

            // Remove old schedule interval
            gate.removeInterval(flight.getFlightNumber());
            flight.addDelay(delayMillis);

            long newStart = flight.getActualStartTime();
            long newEnd = flight.getActualEndTime() + turnaroundBuffer;

            // Attempt to keep same gate if conflict free, otherwise migrates
            if (!gate.hasConflict(newStart, newEnd)) {
                gate.bookInterval(newStart, newEnd, flight.getFlightNumber());
                System.out.println("[ATC] Delayed Flight " + flight.getFlightNumber() + " kept original Gate " + gate.getId());
            } else {
                System.out.println("[ATC] Delayed Flight " + flight.getFlightNumber() + " conflicted with Gate " + gate.getId() + ". Reassigning...");
                flightToGateMap.remove(flight.getFlightNumber());
                Gate newGate = assignGate(flight, turnaroundBuffer);
                System.out.println("[ATC] Migrated Flight " + flight.getFlightNumber() + " to new Gate " + newGate.getId());
            }
        } finally {
            rwLock.writeLock().unlock();
        }
    }

    public Gate getAssignedGate(String flightNumber) {
        return flightToGateMap.get(flightNumber);
    }
}

public class Main {
    public static void main(String[] args) {
        System.out.println("=== INITIALIZING AIRPORT MANAGEMENT ===");
        GateAssignmentService gas = new GateAssignmentService();

        // Register Gates
        // G1: Compatible with Medium and Large jets
        Gate g1 = new Gate("G1", new HashSet<>(Arrays.asList(AircraftType.MEDIUM, AircraftType.LARGE)));
        // G2: Compatible with Medium and Small jets
        Gate g2 = new Gate("G2", new HashSet<>(Arrays.asList(AircraftType.SMALL, AircraftType.MEDIUM)));
        
        gas.addGate(g1);
        gas.addGate(g2);

        long now = System.currentTimeMillis();
        long hour = 3600 * 1000;
        long buffer = 15 * 60 * 1000; // 15 mins buffer

        System.out.println("\\n=== 1. SCHEDULING INITIAL FLIGHTS ===");
        Flight f1 = new Flight("AA101", AircraftType.LARGE, now, 2 * hour);
        Flight f2 = new Flight("UA202", AircraftType.MEDIUM, now + hour, hour);

        try {
            Gate assign1 = gas.assignGate(f1, buffer);
            System.out.println("Assigned " + f1.getFlightNumber() + " to Gate " + assign1.getId());
            
            Gate assign2 = gas.assignGate(f2, buffer);
            System.out.println("Assigned " + f2.getFlightNumber() + " to Gate " + assign2.getId());
        } catch (Exception e) {
            System.out.println("Error: " + e.getMessage());
        }

        System.out.println("\\n=== 2. HANDLING CONFLICT WITH DELAY ===");
        // Flight AA101 (large, occupying G1 from now to now+2h) is delayed by 1 hour.
        // It now occupies from now+1h to now+3h.
        // This conflicts with G1 scheduling.
        try {
            System.out.println("Adding 1 hour delay to Flight AA101...");
            gas.handleFlightDelay(f1, hour, buffer);
        } catch (Exception e) {
            System.out.println("Delay handling failed: " + e.getMessage());
        }
    }
}

๐Ÿ’ฌReview

Help Us Improve

How helpful was this walkthrough?

Click a star to rate. We actively use this feedback to refine and update our system design content.

Placeholder
Optional but highly appreciated!

Discussion

Share your thoughts, ask questions, or help others.

Loading comments...