Machine Coding Problem

Cab Sharing (Uber-lite)

maco30maco60macoAllgeostrategy-patternobserver-patterncompare-and-swap-concurrencygeo-proximity
Commonly Asked By:UberLyftGrabOla

Functional Scope (In-Scope)

  • Rider/Driver Geo Proximity Matches: Find nearby available vehicles inside user-specified coordinates radius grids.
  • Dynamic Pricing Models (Strategy Pattern): Implement surge factors or standard pricing calculated dynamically from supply/demand levels.
  • Observer Trip Lifecycle Notifications: Publish live state changes to both Rider client apps and Driver terminals.
  • Atomic Driver Status CAS flips: Flip driver availability flags atomically using compare-and-swap logic.
  • Trip Lifecycle tracking: Manage ride workflows (Requested, Ongoing, Completed, Cancelled).

Explicit Boundaries (Out-of-Scope)

  • No Real Physical GPS Map Rendering: Bypasses live Leaflet, Google Maps visual wrappers, or vector routing canvases.
  • No Intelligent Shared Carpool Splits: Excludes complex multi-destination waypoint routing or rider-matching optimizations.

Clean reference designs detailing dynamic pricing and trip observers in Java and Python:

// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicReference;

enum DriverStatus { AVAILABLE, ON_TRIP, OFFLINE }
enum TripStatus { REQUESTED, ONGOING, COMPLETED, CANCELLED }

class Location {
    private final double lat;
    private final double lon;

    public Location(double lat, double lon) {
        this.lat = lat;
        this.lon = lon;
    }

    public double getLat() { return lat; }
    public double getLon() { return lon; }

    public double distanceTo(Location other) {
        return Math.sqrt(Math.pow(lat - other.getLat(), 2) + Math.pow(lon - other.getLon(), 2));
    }
}

class Driver {
    private final String id;
    private final String name;
    private final AtomicReference<DriverStatus> status = new AtomicReference<>(DriverStatus.AVAILABLE);
    private volatile Location location;

    public Driver(String id, String name, Location location) {
        this.id = id;
        this.name = name;
        this.location = location;
    }

    public String getId() { return id; }
    public String getName() { return name; }
    public DriverStatus getStatus() { return status.get(); }
    public Location getLocation() { return location; }
    public void setLocation(Location location) { this.location = location; }

    public boolean compareAndSetStatus(DriverStatus expected, DriverStatus update) {
        return status.compareAndSet(expected, update);
    }
}

interface TripObserver {
    void onTripStatusChanged(String tripId, TripStatus newStatus);
}

class RiderNotifier implements TripObserver {
    @Override
    public void onTripStatusChanged(String tripId, TripStatus newStatus) {
        System.out.println(String.format("[Rider App] Trip %s status updated: %s", tripId, newStatus));
    }
}

class DriverNotifier implements TripObserver {
    @Override
    public void onTripStatusChanged(String tripId, TripStatus newStatus) {
        System.out.println(String.format("[Driver Terminal] Trip %s alert: move to state %s", tripId, newStatus));
    }
}

class Trip {
    private final String id;
    private final String riderId;
    private final Driver driver;
    private final Location pickup;
    private final Location drop;
    private final double fare;
    private TripStatus status = TripStatus.REQUESTED;
    private final List<TripObserver> observers = new CopyOnWriteArrayList<>();

    public Trip(String id, String riderId, Driver driver, Location pickup, Location drop, double fare) {
        this.id = id;
        this.riderId = riderId;
        this.driver = driver;
        this.pickup = pickup;
        this.drop = drop;
        this.fare = fare;
    }

    public String getId() { return id; }
    public Driver getDriver() { return driver; }
    public TripStatus getStatus() { return status; }
    public double getFare() { return fare; }

    public void addObserver(TripObserver observer) { observers.add(observer); }

    public synchronized boolean transitionTo(TripStatus next) {
        // Enforce basic trip flow constraints
        if (this.status == TripStatus.COMPLETED || this.status == TripStatus.CANCELLED) {
            return false;
        }
        this.status = next;
        notifyObservers(next);
        return true;
    }

    private void notifyObservers(TripStatus next) {
        for (TripObserver obs : observers) {
            obs.onTripStatusChanged(id, next);
        }
    }
}

// ─── STRATEGY PATTERN (PRICING SYSTEM) ───────────────────────────────────────
interface PricingStrategy {
    double calculateFare(Location start, Location end, int activeDemand, int availableDrivers);
}

class StandardPricingStrategy implements PricingStrategy {
    @Override
    public double calculateFare(Location start, Location end, int activeDemand, int availableDrivers) {
        return start.distanceTo(end) * 10.0;
    }
}

class SurgePricingStrategy implements PricingStrategy {
    @Override
    public double calculateFare(Location start, Location end, int activeDemand, int availableDrivers) {
        double dist = start.distanceTo(end);
        double multiplier = 1.0;
        if (availableDrivers == 0 || ((double) activeDemand / availableDrivers) > 1.5) {
            multiplier = 2.2;
        }
        return dist * 10.0 * multiplier;
    }
}

class CabSharingService {
    private final List<Driver> drivers = new CopyOnWriteArrayList<>();
    private final Map<String, Trip> activeTrips = new ConcurrentHashMap<>();
    private PricingStrategy pricingStrategy;

    public CabSharingService(PricingStrategy strategy) {
        this.pricingStrategy = strategy;
    }

    public void addDriver(Driver d) { drivers.add(d); }
    public void setPricingStrategy(PricingStrategy strategy) { this.pricingStrategy = strategy; }

    public int getAvailableDriversCount() {
        int count = 0;
        for (Driver d : drivers) {
            if (d.getStatus() == DriverStatus.AVAILABLE) count++;
        }
        return count;
    }

    public Trip requestRide(String riderId, Location pickup, Location drop, int activeDemand) {
        Driver bestDriver = null;
        double minDistance = Double.MAX_VALUE;

        for (Driver d : drivers) {
            if (d.getStatus() == DriverStatus.AVAILABLE) {
                double dist = d.getLocation().distanceTo(pickup);
                if (dist < minDistance) {
                    minDistance = dist;
                    bestDriver = d;
                }
            }
        }

        if (bestDriver != null && bestDriver.compareAndSetStatus(DriverStatus.AVAILABLE, DriverStatus.ON_TRIP)) {
            double fare = pricingStrategy.calculateFare(pickup, drop, activeDemand, getAvailableDriversCount() + 1);
            String tripId = "TRIP-" + UUID.randomUUID().toString().substring(0, 8).toUpperCase();
            
            Trip trip = new Trip(tripId, riderId, bestDriver, pickup, drop, fare);
            trip.addObserver(new RiderNotifier());
            trip.addObserver(new DriverNotifier());

            activeTrips.put(tripId, trip);
            trip.transitionTo(TripStatus.ONGOING);
            System.out.println(String.format("[Service] Rider %s matched with Driver %s. Fare: $%.2f", 
                    riderId, bestDriver.getName(), fare));
            return trip;
        }

        System.out.println("[Service] Ride Request Failed: No available drivers close to Rider: " + riderId);
        return null;
    }

    public void completeTrip(String tripId) {
        Trip trip = activeTrips.get(tripId);
        if (trip != null && trip.transitionTo(TripStatus.COMPLETED)) {
            trip.getDriver().compareAndSetStatus(DriverStatus.ON_TRIP, DriverStatus.AVAILABLE);
            System.out.println("[Service] Trip " + tripId + " successfully completed.");
        }
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        System.out.println("=== Cab Sharing Simulation ===");
        CabSharingService service = new CabSharingService(new SurgePricingStrategy());

        service.addDriver(new Driver("DRV-01", "Adam", new Location(1.0, 1.0)));
        service.addDriver(new Driver("DRV-02", "Bella", new Location(2.0, 2.0)));

        Location riderPickup = new Location(1.2, 1.2);
        Location riderDrop = new Location(10.0, 10.0);

        // High demand, low driver supply -> Surge applies
        System.out.println("\n--- Requesting Ride under High Demand (Surge Mode) ---");
        Trip trip1 = service.requestRide("RIDER-A", riderPickup, riderDrop, 8);

        // Complete trip to return driver to availability pool
        if (trip1 != null) {
            service.completeTrip(trip1.getId());
        }

        System.out.println("\n--- Requesting Ride under Low Demand (Standard Mode) ---");
        service.setPricingStrategy(new StandardPricingStrategy());
        Trip trip2 = service.requestRide("RIDER-B", riderPickup, riderDrop, 1);
    }
}