//obstacle mock try this on this online compiler https://w...content-available-to-author-only...b.com/online_java_compiler# 
import java.util.*;

/**
 * =====================================================================
 * OBSTACLE COURSE — Karat Interview
 * =====================================================================
 *
 * We are writing software to collect and manage data on how fast racers
 * complete obstacle courses. An obstacle course is a series of physical
 * challenges that a racer must go through.
 *
 * A "run" is one attempt at an obstacle course.
 * A "run collection" is a group of runs on a particular course.
 * Each obstacle has a time recorded for it.
 * A run may be incomplete (racer didn't finish all obstacles).
 *
 * Example data:
 *   Obstacles:    O1  O2  O3  O4
 *   Run 1:         3   4   5   6
 *   Run 2:         4   4   4   5
 *   Run 3:         4   5   4   6
 *   Run 4:         5   5   3        (incomplete)
 *
 * TASK 1: The tests are failing. Read the code, find the bug, fix it.
 *
 * TASK 2: Implement bestOfBests().
 *   This is a measure of how fast a run could be if everything went
 *   perfectly. It is determined by taking the fastest time for each
 *   obstacle across all runs (even incomplete ones) and summing them.
 *   In the example above: 3, 4, 3, 5 → best of bests = 15 seconds.
 *
 * TASK 3: Implement chanceOfPersonalBest(Run inProgressRun).
 *   Given an in-progress run, simulate 10,000 trials. For each
 *   remaining obstacle, randomly pick a time from that obstacle's
 *   historical times across all existing runs. Return the fraction
 *   of trials where the simulated total <= personalBest().
 */

class Course {
    public String title;
    public int obstacleCount;

    public Course(String title, int obstacleCount) {
        this.title = title;
        this.obstacleCount = obstacleCount;
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Course)) return false;
        Course c = (Course) o;
        return title.equals(c.title) && obstacleCount == c.obstacleCount;
    }
}

class Run {
    public Course course;
    public boolean complete;
    public List<Integer> obstacleTimes;

    public Run(Course course) {
        this.course = course;
        this.complete = false;
        this.obstacleTimes = new ArrayList<>();
    }

    public void addObstacleTime(int time) {
        if (complete) throw new IllegalStateException("Cannot add obstacle to complete run");
        obstacleTimes.add(time);
        if (obstacleTimes.size() == course.obstacleCount) {
            complete = true;
        }
    }

    public int getRunTime() {
        int total = 0;
        for (int t : obstacleTimes) total += t;
        return total;
    }
}

class RunCollection {
    public List<Run> runs;
    public Course course;

    public RunCollection(Course course) {
        this.runs = new ArrayList<>();
        this.course = course;
    }

    public int getNumRuns() {
        return runs.size();
    }

    public void addRun(Run run) {
        if (!run.course.equals(course)) {
            throw new IllegalArgumentException("Run's course doesn't match collection's course");
        }
        runs.add(run);
    }

    // TASK 1: This method has a bug. Find and fix it.
    // Returns the fastest complete run time (personal best).
    public int personalBest() {
        return runs.stream().mapToInt(r -> r.getRunTime()).min().orElse(Integer.MAX_VALUE);
    }

    /**
     * TASK 2: Best of bests.
     * Sum of the fastest time per obstacle across ALL runs (including incomplete).
     */
    public int bestOfBests() {
        // TODO: implement
        return 0;
    }

    /**
     * TASK 3: Chance of personal best.
     * Simulates 10,000 trials completing inProgressRun with random historical times.
     */
    public double chanceOfPersonalBest(Run inProgressRun) {
        // TODO: implement
        return 0.0;
    }
}

public class Main {

    private static int passed = 0, failed = 0;

    public static void main(String[] args) {
        System.out.println("\n=== OBSTACLE COURSE — KARAT PRACTICE ===\n");

        run("TASK 0 — Run basics", Main::testRun);
        run("TASK 1 — Personal best", Main::testRunCollection);
        run("TASK 2 — Best of bests", Main::testBestOfBests);
        run("TASK 3 — Chance of personal best", Main::testChanceOfPersonalBest);

        System.out.println("\n--------------------------------------------------");
        System.out.println("Results: " + passed + " passed, " + failed +
                           " failed out of " + (passed + failed));
    }

    private static RunCollection makeRunCollection(Course course, int[][] data) {
        RunCollection rc = new RunCollection(course);
        for (int[] times : data) {
            Run run = new Run(course);
            for (int t : times) run.addObstacleTime(t);
            rc.addRun(run);
        }
        return rc;
    }

    public static void testRun() {
        Course c = new Course("Test", 2);
        Run r = new Run(c);
        r.addObstacleTime(3);
        assert !r.complete : "Should not be complete yet";
        r.addObstacleTime(5);
        assert r.complete : "Should be complete now";
        assert r.getRunTime() == 8 : "Run time should be 8";
        try {
            r.addObstacleTime(4);
            throw new AssertionError("Should have thrown exception");
        } catch (IllegalStateException e) {
            // expected
        }
    }

    public static void testRunCollection() {
        Course c = new Course("Test", 4);
        int[][] data = {{3,4,5,6}, {4,4,4,5}, {4,5,4,6}, {5,5,3}};
        RunCollection rc = makeRunCollection(c, data);

        assert rc.getNumRuns() == 4 : "Should have 4 runs";
        assert rc.personalBest() == 17 :
            "Personal best should be 17, was " + rc.personalBest();
    }

    public static void testBestOfBests() {
        Course c = new Course("Test", 4);
        int[][] data = {{3,4,5,6}, {4,4,4,5}, {4,5,4,6}, {5,5,3}};
        RunCollection rc = makeRunCollection(c, data);

        int bob = rc.bestOfBests();
        assert bob != 0 : "bestOfBests() not implemented (returned 0)";
        assert bob == 15 :
                "Best of bests should be 15, was " + bob;
    }
    public static void testChanceOfPersonalBest() {
        Course c1 = new Course("Test", 3);
        int[][] data1 = {{3,3,2}, {3,3,3}};
        RunCollection rc1 = makeRunCollection(c1, data1);
        Run test1 = new Run(c1);
        test1.addObstacleTime(3);
        test1.addObstacleTime(3);
        double chance1 = rc1.chanceOfPersonalBest(test1);
        assert chance1 != 0.0 : "chanceOfPersonalBest() not implemented (returned 0.0)";
        assert chance1 >= 0.48 && chance1 <= 0.52 :
                "Chance should be ~0.50, was " + chance1;

        Course c2 = new Course("Test", 4);
        int[][] data2 = {{3,3,2,3}, {3,3,3,2}, {5,5,2}};
        RunCollection rc2 = makeRunCollection(c2, data2);
        Run test2 = new Run(c2);
        test2.addObstacleTime(3);
        test2.addObstacleTime(3);
        double chance2 = rc2.chanceOfPersonalBest(test2);
        assert chance2 != 0.0 : "chanceOfPersonalBest() not implemented (returned 0.0)";
        assert chance2 >= 0.813 && chance2 <= 0.853 :
                "Chance should be ~0.833, was " + chance2;
    }

    // ================================================================
    //                      HELPERS
    // ================================================================

    private static void run(String name, Runnable test) {
        try {
            test.run();
            passed++;
            System.out.println("  PASS: " + name);
        } catch (Exception | AssertionError e) {
            failed++;
            System.out.println("  FAIL: " + name + " -> " + e.getMessage());
        }
    }

}
