Functional Scope (In-Scope)
- Match Hierarchy Structuring: Support structured Innings, Overs, and Ball records cleanly.
- Dynamic Score Calculations: Automatically aggregate totals, wickets, and averages as balls are inputted.
- Decoupled Observer Dashboard updates: Register and update multiple frontend, notifications, and analytics platforms dynamically.
- Flexible Final Score Projection: Support multiple strategy-based calculations for forecasting match outcomes.
- Ball Commentary Logs: Record commentary entries for each delivery.
Explicit Boundaries (Out-of-Scope)
- No Intelligent Video Streaming Rendering: Does not stream media frames or process live video feeds.
- No Ticket Sales / Gate Management: Strictly handles cricket match stats and commentators scoring inputs.
Thread-safe real-time scoring blueprints in Java and Python:
// ─── JAVA BLUEPRINT ──────────────────────────────────────────────────────────
import java.util.*;
import java.util.concurrent.*;
import java.util.concurrent.locks.*;
enum OutcomeType {
RUNS, WICKET, EXTRA_WIDE, EXTRA_NO_BALL, BYE
}
class Delivery {
private final int over;
private final int ball;
private final String bowler;
private final String batsman;
private final int runs;
private final OutcomeType type;
private final String commentary;
public Delivery(int over, int ball, String bowler, String batsman, int runs, OutcomeType type, String commentary) {
this.over = over;
this.ball = ball;
this.bowler = bowler;
this.batsman = batsman;
this.runs = runs;
this.type = type;
this.commentary = commentary;
}
public int getOver() { return over; }
public int getBall() { return ball; }
public String getBowler() { return bowler; }
public String getBatsman() { return batsman; }
public int getRuns() { return runs; }
public OutcomeType getType() { return type; }
public String getCommentary() { return commentary; }
}
interface ProjectionStrategy {
int projectFinalScore(int currentRuns, int ballsBowled, int totalBalls, int wickets);
}
class CurrentRunRateProjector implements ProjectionStrategy {
@Override
public int projectFinalScore(int currentRuns, int ballsBowled, int totalBalls, int wickets) {
if (ballsBowled == 0) return 0;
double crr = (double) currentRuns / ((double) ballsBowled / 6.0);
return (int) Math.round(crr * (totalBalls / 6.0));
}
}
class DefensiveMatchProjector implements ProjectionStrategy {
@Override
public int projectFinalScore(int currentRuns, int ballsBowled, int totalBalls, int wickets) {
int remainingBalls = totalBalls - ballsBowled;
int remainingOvers = remainingBalls / 6;
int expectedRate = (wickets > 7) ? 4 : (wickets > 4) ? 6 : 8;
return currentRuns + (remainingOvers * expectedRate);
}
}
interface ScoreObserver {
void onScoreUpdate(String matchId, int runs, int wickets, double overs, int projectedScore, String commentary);
}
class WebDashboardObserver implements ScoreObserver {
@Override
public void onScoreUpdate(String matchId, int runs, int wickets, double overs, int projectedScore, String commentary) {
System.out.println(String.format("[Web Dashboard] Match: %s | Score: %d/%d (%.1f overs) | Projected Score: %d | Last Action: %s",
matchId, runs, wickets, overs, projectedScore, commentary));
}
}
class FantasySportsObserver implements ScoreObserver {
@Override
public void onScoreUpdate(String matchId, int runs, int wickets, double overs, int projectedScore, String commentary) {
System.out.println(String.format("[Fantasy Platform] Syncing points for Match %s. Live score runs: %d", matchId, runs));
}
}
class MatchScorecard {
private final String matchId;
private final int totalBalls = 300; // 50-over match
private int totalRuns = 0;
private int wickets = 0;
private int ballsBowled = 0;
private final List<Delivery> deliveries = new ArrayList<>();
private final List<ScoreObserver> observers = new CopyOnWriteArrayList<>();
private ProjectionStrategy projectionStrategy;
private final ReadWriteLock lock = new ReentrantReadWriteLock();
public MatchScorecard(String matchId, ProjectionStrategy initialStrategy) {
this.matchId = matchId;
this.projectionStrategy = initialStrategy;
}
public void addObserver(ScoreObserver obs) {
observers.add(obs);
}
public void removeObserver(ScoreObserver obs) {
observers.remove(obs);
}
public void setProjectionStrategy(ProjectionStrategy strategy) {
lock.writeLock().lock();
try {
this.projectionStrategy = strategy;
} finally {
lock.writeLock().unlock();
}
}
public void recordBall(int over, int ball, String bowler, String batsman, int runs, OutcomeType type, String extraCommentary) {
lock.writeLock().lock();
try {
int runsScored = runs;
if (type == OutcomeType.EXTRA_WIDE || type == OutcomeType.EXTRA_NO_BALL) {
runsScored += 1;
}
if (type == OutcomeType.WICKET) {
wickets++;
}
totalRuns += runsScored;
if (type != OutcomeType.EXTRA_WIDE && type != OutcomeType.EXTRA_NO_BALL) {
ballsBowled++;
}
String commentary = String.format("Over %d.%d: %s to %s -> %s (Runs: %d)",
over, ball, bowler, batsman, type, runsScored);
if (extraCommentary != null && !extraCommentary.isEmpty()) {
commentary += " | " + extraCommentary;
}
Delivery delivery = new Delivery(over, ball, bowler, batsman, runsScored, type, commentary);
deliveries.add(delivery);
double overs = (ballsBowled / 6) + ((ballsBowled % 6) / 10.0);
int projected = projectionStrategy.projectFinalScore(totalRuns, ballsBowled, totalBalls, wickets);
notifyObservers(overs, projected, commentary);
} finally {
lock.writeLock().unlock();
}
}
private void notifyObservers(double overs, int projected, String commentary) {
for (ScoreObserver obs : observers) {
obs.onScoreUpdate(matchId, totalRuns, wickets, overs, projected, commentary);
}
}
}
public class Main {
public static void main(String[] args) throws InterruptedException {
System.out.println("=== Cricbuzz Scoreboard Concurrent Simulation ===");
MatchScorecard scorecard = new MatchScorecard("IND-vs-AUS-2026", new CurrentRunRateProjector());
ScoreObserver dashboard = new WebDashboardObserver();
ScoreObserver fantasy = new FantasySportsObserver();
scorecard.addObserver(dashboard);
scorecard.addObserver(fantasy);
ExecutorService executor = Executors.newFixedThreadPool(2);
executor.submit(() -> {
scorecard.recordBall(1, 1, "Mitchell Starc", "Rohit Sharma", 4, OutcomeType.RUNS, "Stunning drive!");
scorecard.recordBall(1, 2, "Mitchell Starc", "Rohit Sharma", 0, OutcomeType.WICKET, "Bowled him!");
});
executor.submit(() -> {
try { Thread.sleep(50); } catch (InterruptedException ignored) {}
scorecard.recordBall(1, 3, "Mitchell Starc", "Virat Kohli", 1, OutcomeType.RUNS, "Quick single");
});
executor.shutdown();
executor.awaitTermination(2, TimeUnit.SECONDS);
System.out.println("\n--- Switching Scorecard to Defensive Projection Strategy ---");
scorecard.setProjectionStrategy(new DefensiveMatchProjector());
scorecard.recordBall(1, 4, "Mitchell Starc", "Shubman Gill", 6, OutcomeType.RUNS, "Massive pull shot!");
}
}