Cricket-App / app.py
neerajkalyank's picture
Update app.py
4018b70 verified
import gradio as gr
import pandas as pd
from typing import List, Dict, Tuple
# Store match data
matches = {}
current_match = None
def validate_player_names(players_str: str) -> Tuple[List[str], str]:
"""Validate and clean player names input."""
if not players_str.strip():
return [], "Player names cannot be empty"
players = []
errors = []
for i, p in enumerate(players_str.split(",")):
p = p.strip().rstrip('.').strip() # Clean the name
if not p:
continue # Skip empty entries
if len(p) > 20:
errors.append(f"Name too long: '{p}' (max 20 chars)")
elif not p.replace(" ", "").isalnum():
errors.append(f"Invalid characters in name: '{p}'")
else:
players.append(p)
error_msg = "\n".join(errors) if errors else ""
return players, error_msg
def create_match(team1_name: str, team2_name: str,
players_team1: str, players_team2: str,
total_overs: int) -> Tuple[str, str, dict]:
"""Create a new cricket match with validation."""
global matches
try:
# Validate team names
if not team1_name.strip() or not team2_name.strip():
return "Both team names are required!", "", gr.update(choices=list(matches.keys()))
if team1_name.strip().lower() == team2_name.strip().lower():
return "Team names must be different!", "", gr.update(choices=list(matches.keys()))
# Validate overs
try:
total_overs = int(total_overs)
if total_overs <= 0:
return "Overs must be a positive number!", "", gr.update(choices=list(matches.keys()))
except ValueError:
return "Overs must be a number!", "", gr.update(choices=list(matches.keys()))
# Process player names
players1, error1 = validate_player_names(players_team1)
players2, error2 = validate_player_names(players_team2)
if error1 or error2:
error_msg = "Errors in player names:\n"
if error1:
error_msg += f"Team 1: {error1}\n"
if error2:
error_msg += f"Team 2: {error2}"
return error_msg.strip(), "", gr.update(choices=list(matches.keys()))
if len(players1) < 1 or len(players2) < 1:
return "Each team must have at least 1 player!", "", gr.update(choices=list(matches.keys()))
# Create match ID
match_id = f"{team1_name.strip()} vs {team2_name.strip()}"
if match_id in matches:
return "Match already exists!", "", gr.update(choices=list(matches.keys()))
# Initialize match data
matches[match_id] = {
"teams": {
team1_name.strip(): {
"players": players1,
"runs": 0,
"wickets": 0,
"overs": 0.0,
"extras": 0
},
team2_name.strip(): {
"players": players2,
"runs": 0,
"wickets": 0,
"overs": 0.0,
"extras": 0
}
},
"batting_order": {team1_name.strip(): [], team2_name.strip(): []},
"bowling_figures": {team1_name.strip(): {}, team2_name.strip(): {}},
"current_batting": team1_name.strip(),
"current_bowling": team2_name.strip(),
"total_overs": total_overs,
"completed": False,
"first_innings": None
}
# Initialize bowling figures
for player in players1:
matches[match_id]["bowling_figures"][team1_name.strip()][player] = {
"runs": 0,
"wickets": 0,
"overs": 0.0,
"maidens": 0
}
for player in players2:
matches[match_id]["bowling_figures"][team2_name.strip()][player] = {
"runs": 0,
"wickets": 0,
"overs": 0.0,
"maidens": 0
}
return (f"Match created: {match_id}\n{team1_name} to bat first!",
match_id,
gr.update(choices=list(matches.keys()), value=match_id))
except Exception as e:
return f"Error: {str(e)}", "", gr.update(choices=list(matches.keys()))
def update_team_choices(match_id: str) -> dict:
"""Update team choices for the batting team dropdown."""
if match_id in matches:
teams = list(matches[match_id]["teams"].keys())
return gr.update(choices=teams, value=matches[match_id]["current_batting"])
return gr.update(choices=[], value=None)
def update_score(match_id: str, batting_team: str, runs: int,
is_wicket: bool, bowler: str, batsman: str,
balls_bowled: int, extras: int) -> Tuple[str, str, str]:
"""Update the match score with validation."""
if match_id not in matches:
return "Match not found!", "", ""
match = matches[match_id]
# Validate inputs
try:
runs = int(runs)
balls_bowled = int(balls_bowled)
extras = int(extras)
except ValueError:
return "Runs, balls and extras must be numbers!", "", ""
if batting_team not in match["teams"]:
return "Invalid batting team!", "", ""
if bowler not in match["teams"][match["current_bowling"]]["players"]:
return "Bowler not found in bowling team!", "", ""
if batsman not in match["teams"][batting_team]["players"]:
return "Batsman not found in batting team!", "", ""
if balls_bowled <= 0 or balls_bowled > 6:
return "Balls bowled must be between 1-6!", "", ""
# Update score
match["teams"][batting_team]["runs"] += runs + extras
match["teams"][batting_team]["extras"] += extras
if is_wicket:
match["teams"][batting_team]["wickets"] += 1
# Update batting order
if batsman not in match["batting_order"][batting_team]:
match["batting_order"][batting_team].append(batsman)
# Update bowler figures
bowler_stats = match["bowling_figures"][match["current_bowling"]][bowler]
bowler_stats["runs"] += runs + extras
if is_wicket:
bowler_stats["wickets"] += 1
# Update overs (convert balls to fractional overs)
over_fraction = balls_bowled / 6
bowler_stats["overs"] += over_fraction
match["teams"][batting_team]["overs"] += over_fraction
# Check for maiden over (0 runs in full over)
if balls_bowled == 6 and runs + extras == 0:
bowler_stats["maidens"] += 1
# Check innings completion
if (match["teams"][batting_team]["wickets"] >= len(match["teams"][batting_team]["players"]) - 1 or
match["teams"][batting_team]["overs"] >= match["total_overs"]):
if match["first_innings"] is None:
# First innings completed
match["first_innings"] = match["teams"][batting_team]["runs"]
match["current_batting"] = match["current_bowling"]
match["current_bowling"] = batting_team
target = match["first_innings"] + 1
return ("Innings completed! Teams will switch.\n"
f"Target: {target}",
f"{batting_team}: {match['teams'][batting_team]['runs']}/{match['teams'][batting_team]['wickets']}",
generate_scorecard(match_id))
else:
# Match completed
match["completed"] = True
result = determine_result(match)
return ("Match completed!\n" + result,
f"{batting_team}: {match['teams'][batting_team]['runs']}/{match['teams'][batting_team]['wickets']}",
generate_scorecard(match_id))
# Prepare current score display
score = (f"{batting_team}: {match['teams'][batting_team]['runs']}/"
f"{match['teams'][batting_team]['wickets']} "
f"({match['teams'][batting_team]['overs']:.1f} ov)")
if match["first_innings"] is not None:
runs_needed = match["first_innings"] + 1 - match["teams"][batting_team]["runs"]
score += f" | Target: {match['first_innings'] + 1} | Need: {runs_needed}"
return "Score updated!", score, generate_scorecard(match_id)
def determine_result(match: Dict) -> str:
"""Determine the result of the match."""
team1, team2 = list(match["teams"].keys())
runs1 = match["teams"][team1]["runs"]
runs2 = match["teams"][team2]["runs"]
if runs1 > runs2:
return f"{team1} won by {runs1 - runs2} runs"
elif runs2 > runs1:
return f"{team2} won by {runs2 - runs1} runs"
else:
return "Match tied!"
def generate_scorecard(match_id: str) -> str:
"""Generate detailed scorecard for the match."""
if match_id not in matches:
return "Match not found!"
match = matches[match_id]
output = []
for team_name, team_data in match["teams"].items():
output.append(f"### {team_name}")
output.append(f"Total: {team_data['runs']}/{team_data['wickets']} "
f"in {team_data['overs']:.1f} overs (Extras: {team_data['extras']})")
# Batting details
output.append("\n**Batting:**")
for player in match["batting_order"][team_name]:
output.append(f"- {player}")
# Bowling details
output.append("\n**Bowling Figures:**")
for bowler, figures in match["bowling_figures"].get(team_name, {}).items():
output.append(f"- {bowler}: {figures['runs']}-{figures['wickets']} "
f"({figures['overs']:.1f} ov, {figures['maidens']} maidens)")
# Match status
if match["completed"]:
output.append("\n**RESULT:** " + determine_result(match))
elif match["first_innings"] is not None:
output.append(f"\nTarget: {match['first_innings'] + 1}")
return "\n".join(output)
with gr.Blocks(title="Gully Cricket Scorecard", theme="soft") as app:
gr.Markdown("# 🏏 Gully Cricket Scorecard")
gr.Markdown("Track your local cricket matches with this simple scorecard app!")
with gr.Tab("Create Match"):
with gr.Row():
with gr.Column():
team1 = gr.Textbox(label="Team 1 Name", placeholder="Enter team 1 name")
players1 = gr.Textbox(label="Team 1 Players",
placeholder="Comma separated names (e.g., Virat, Rohit, Bumrah)")
with gr.Column():
team2 = gr.Textbox(label="Team 2 Name", placeholder="Enter team 2 name")
players2 = gr.Textbox(label="Team 2 Players",
placeholder="Comma separated names (e.g., Dhoni, Jadeja, Rahul)")
overs = gr.Number(label="Total Overs", value=5, minimum=1, maximum=50, step=1)
create_btn = gr.Button("Create Match", variant="primary")
match_output = gr.Textbox(label="Status", interactive=False)
match_id = gr.Textbox(visible=False)
match_selector_create = gr.Dropdown(
label="Select Match",
choices=list(matches.keys()),
interactive=True
)
with gr.Tab("Update Score"):
with gr.Row():
with gr.Column():
match_selector_update = gr.Dropdown(label="Select Match", choices=list(matches.keys()), interactive=True)
batting_team = gr.Dropdown(label="Batting Team", choices=[], interactive=True)
runs = gr.Number(label="Runs scored this ball", value=0, minimum=0, step=1)
is_wicket = gr.Checkbox(label="Wicket fell?", value=False)
extras = gr.Number(label="Extras (wides, no-balls)", value=0, step=1)
with gr.Column():
bowler = gr.Textbox(label="Bowler", placeholder="Name of current bowler")
batsman = gr.Textbox(label="Batsman", placeholder="Name of current batsman")
balls = gr.Number(label="Balls bowled this update", value=1, minimum=1, maximum=6, step=1)
update_btn = gr.Button("Update Score", variant="primary")
score_output = gr.Textbox(label="Current Score", interactive=False)
scorecard = gr.Textbox(label="Scorecard", interactive=False, lines=20)
# Update batting team choices when match selector is changed
match_selector_update.change(
fn=update_team_choices,
inputs=[match_selector_update],
outputs=[batting_team]
)
# Create match
create_btn.click(
fn=create_match,
inputs=[team1, team2, players1, players2, overs],
outputs=[match_output, match_id, match_selector_create]
)
# Update score
update_btn.click(
fn=update_score,
inputs=[match_selector_update, batting_team, runs, is_wicket, bowler, batsman, balls, extras],
outputs=[match_output, score_output, scorecard]
)
# Launch the app
if __name__ == "__main__":
app.launch()