Spaces:
Sleeping
Sleeping
| import base64 | |
| import json | |
| from datetime import datetime, timedelta | |
| import pandas as pd | |
| import pytz | |
| import streamlit as st | |
| # File paths as constants | |
| PREDICTIONS_CSV = 'predictions.csv' | |
| USERS_JSON = 'users.json' | |
| MATCHES_JSON = 'matches.json' | |
| OUTCOMES_JSON = 'match_outcomes.json' | |
| PLAYERS_JSON = 'players.json' | |
| image_path = 'ipl_image.png' | |
| # Initialize CSV and JSON files if they don't exist | |
| def initialize_files(): | |
| # Initialize predictions CSV | |
| try: | |
| pd.read_csv(PREDICTIONS_CSV) | |
| except FileNotFoundError: | |
| df = pd.DataFrame(columns=['user_name', 'match_id', 'predicted_winner', 'predicted_motm', 'bid_points']) | |
| df.to_csv(PREDICTIONS_CSV, index=False) | |
| def load_data(file_path): | |
| """ | |
| Load data from a JSON or CSV file. | |
| Args: | |
| file_path (str): The path to the file to load. | |
| Returns: | |
| pd.DataFrame or dict: The loaded data. | |
| """ | |
| try: | |
| if file_path.endswith('.json'): | |
| with open(file_path, 'r') as file: | |
| return json.load(file) | |
| elif file_path.endswith('.csv'): | |
| return pd.read_csv(file_path) | |
| except FileNotFoundError: | |
| if file_path.endswith('.json'): | |
| return {} | |
| elif file_path.endswith('.csv'): | |
| return pd.DataFrame() | |
| def get_base64_of_image(path): | |
| with open(path, "rb") as image_file: | |
| return base64.b64encode(image_file.read()).decode() | |
| # Get today's date in IST to load today's match | |
| def get_current_date_ist(): | |
| tz_IST = pytz.timezone('Asia/Kolkata') | |
| datetime_ist = datetime.now(tz_IST) | |
| return datetime_ist.strftime('%Y-%m-%d') | |
| # Function to get matches for today | |
| def get_today_matches(): | |
| today = get_current_date_ist() | |
| matches = load_data(MATCHES_JSON) | |
| today_matches = [match for match in matches if match['date'] == today] | |
| return today_matches | |
| # Function to check if prediction submission is allowed | |
| def is_submission_allowed(match_id): | |
| matches = load_data(MATCHES_JSON) # This loads matches correctly with IST times | |
| for match in matches: | |
| if match["match_id"] == match_id: | |
| # Parse the match start time in IST | |
| tz_IST = pytz.timezone('Asia/Kolkata') | |
| match_datetime_str = f'{match["date"]} {match["time"]}' | |
| # The match time string is like "2024-03-21 7:30 PM" | |
| match_datetime = datetime.strptime(match_datetime_str, "%Y-%m-%d %I:%M %p") | |
| match_datetime = tz_IST.localize(match_datetime) # Set the timezone to IST | |
| # Get the current time in IST | |
| current_datetime = datetime.now(tz_IST) | |
| if current_datetime > match_datetime + timedelta(minutes=30): | |
| return False | |
| else: | |
| return True | |
| return False # If match_id not found, default to False | |
| # Submit prediction function | |
| def submit_prediction( | |
| user_name, | |
| match_id, | |
| predicted_winner, | |
| predicted_motm, | |
| bid_points, | |
| max_bid_points | |
| ): | |
| # Validation for user selection | |
| if user_name == "Select a user...": | |
| st.warning("Please select a valid user.") | |
| return | |
| # Check if prediction submission is allowed for the match | |
| if not is_submission_allowed(match_id): | |
| st.error("Prediction submission time has passed. Predictions can't be submitted after match start.") | |
| return | |
| if bid_points > max_bid_points: | |
| st.error(f"Your bid points exceed the 20% limit of your total points. Maximum allowed bid points: {max_bid_points}") | |
| return | |
| # Ensure predictions DataFrame is loaded or initialized correctly | |
| try: | |
| predictions = load_predictions(PREDICTIONS_CSV) | |
| # Check if all expected columns are present, if not, reinitialize the DataFrame | |
| expected_columns = ['user_name', 'match_id', 'predicted_winner', 'predicted_motm', 'bid_points'] | |
| if not all(column in predictions.columns for column in expected_columns): | |
| raise ValueError("CSV file missing one or more columns; Reinitializing.") | |
| except (FileNotFoundError, ValueError) as e: | |
| predictions = pd.DataFrame(columns=expected_columns) | |
| # Check for duplicate prediction for the same match by the same user | |
| if user_name != "Select a user...": | |
| existing_predictions = predictions[(predictions['user_name'] == user_name) & (predictions['match_id'] == match_id)] | |
| if not existing_predictions.empty: | |
| st.error("You've already submitted a prediction for this match.") | |
| return | |
| # Append new prediction | |
| new_prediction = { | |
| 'user_name': user_name, | |
| 'match_id': match_id, | |
| 'predicted_winner': predicted_winner, | |
| 'predicted_motm': predicted_motm, | |
| 'bid_points': bid_points | |
| } | |
| predictions = pd.concat([predictions, pd.DataFrame([new_prediction])], ignore_index=True) | |
| predictions.to_csv(PREDICTIONS_CSV, index=False) | |
| st.success("Prediction submitted successfully!") | |
| def get_user_total_points(user_name): | |
| users = load_data(USERS_JSON) | |
| return users.get(user_name, 0) | |
| # Define the new function | |
| def calculate_max_bid_points(user_name): | |
| total_points = get_user_total_points(user_name) | |
| max_bid_points = int(total_points * 0.20) # 20% of total points | |
| return max_bid_points | |
| def user_selection_and_prediction(): | |
| users = list(load_data(USERS_JSON)) | |
| user_name = st.selectbox("Select User", ["Select a user..."] + users) | |
| max_bid_points = None | |
| if user_name != "Select a user...": | |
| max_bid_points = calculate_max_bid_points(user_name) | |
| st.write(f"Maximum bid points you can submit: {max_bid_points}") | |
| matches = get_today_matches() | |
| if matches: | |
| match_choice = st.selectbox("Select Today's Match", matches, format_func=lambda match: f"{match['teams'][0]} vs {match['teams'][1]}") | |
| match_id = match_choice['match_id'] | |
| teams = match_choice['teams'] | |
| predicted_winner = st.selectbox("Predicted Winner", teams) | |
| player_list = load_data(PLAYERS_JSON) | |
| predicted_motm = "" | |
| if predicted_winner in player_list: | |
| players = player_list[predicted_winner] | |
| predicted_motm = st.selectbox("Predicted Man of the Match", players) | |
| bid_points = st.number_input("Bid Points", min_value=1, value=100, format="%d") | |
| if st.button("Submit Prediction"): | |
| submit_prediction(user_name, match_id, predicted_winner, predicted_motm, bid_points, max_bid_points) | |
| else: | |
| st.write("No matches are scheduled for today.") | |
| def display_predictions(): | |
| if st.button("Show Predictions"): | |
| try: | |
| todays_predictions = show_todays_match_predictions() | |
| if not todays_predictions.empty: | |
| st.dataframe(todays_predictions, hide_index=True) | |
| else: | |
| st.write("No predictions for today's matches yet.") | |
| except FileNotFoundError: | |
| st.write("No predictions have been submitted yet.") | |
| def display_leaderboard(): | |
| if st.button("Show Leaderboard"): | |
| try: | |
| users = load_data(USERS_JSON) # Adjusted for the new load_data function | |
| leaderboard = sorted(users.items(), key=lambda x: x[1], reverse=True) | |
| # Generate a list of dictionaries, each representing a row in the leaderboard | |
| leaderboard_dicts = [{"Rank": rank+1, "User": user[0], "Points": user[1]} | |
| for rank, user in enumerate(leaderboard)] | |
| # Convert the list of dictionaries to a DataFrame | |
| df_leaderboard = pd.DataFrame(leaderboard_dicts) | |
| st.dataframe(df_leaderboard, hide_index=True) | |
| except FileNotFoundError: | |
| st.write("Leaderboard data not available.") | |
| def load_predictions(PREDICTIONS_CSV): | |
| try: | |
| return pd.read_csv(PREDICTIONS_CSV) | |
| except FileNotFoundError: | |
| return pd.DataFrame() | |
| # Show Predictions functionality | |
| def show_todays_match_predictions(): | |
| # Get today's matches | |
| today_matches = get_today_matches() | |
| today_match_ids = [match['match_id'] for match in today_matches] | |
| # Load all predictions | |
| predictions = load_predictions(PREDICTIONS_CSV) | |
| # Filter predictions for today's matches | |
| today_predictions = predictions[predictions['match_id'].isin(today_match_ids)] | |
| return today_predictions | |
| # Streamlit UI | |
| encoded_image = get_base64_of_image(image_path) | |
| custom_css = f""" | |
| <style> | |
| .header {{ | |
| font-size: 50px; | |
| color: #FFD700; /* Gold */ | |
| text-shadow: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000; /* Black text shadow */ | |
| text-align: center; | |
| padding: 10px; | |
| background-image: url('data:image/png;base64,{encoded_image}'); | |
| background-size: cover; | |
| }} | |
| </style> | |
| """ | |
| # Apply custom CSS | |
| st.markdown(custom_css, unsafe_allow_html=True) | |
| # Use the custom class in a div with your title | |
| st.markdown('<div class="header">DIS IPL Match Predictions</div>', unsafe_allow_html=True) | |
| st.write("π Predict, Compete, and Win π - Where Every Guess Counts! π") | |
| user_guide_content = """ | |
| ### π User Guide | |
| #### Submitting Predictions | |
| - **Match Selection**: Choose the match you want to predict from today's available matches. | |
| - **Team and Player Prediction**: Select the team you predict will win and the "Man of the Match". | |
| - **Bid Points**: Enter the number of points you wish to bid on your prediction. Remember, the maximum you can bid is capped at 20% of your total points. | |
| #### Scoring System | |
| - **Winning Team Prediction**: Correct predictions earn you 1000 points, while incorrect predictions deduct 200 points. | |
| - **Man of the Match Prediction**: Correctly predicting the "Man of the Match" awards you 200 points. No penalty for incorrect guesses. | |
| - **Bonus Points**: An additional 200 points bonus is awarded for getting both the team and "Man of the Match" predictions right. | |
| #### Bid Point Constraints | |
| - You cannot bid more than 20% of your current total points. | |
| - Bid points will be doubled if your prediction is correct, and deducted if incorrect. | |
| #### Rules for Submission | |
| - Predictions must be submitted before the match starts. | |
| - Only one prediction per match is allowed. | |
| - Review your prediction carefully before submission, as it cannot be changed once submitted. | |
| """ | |
| # User Guide as an expander | |
| with st.expander("User Guide π"): | |
| st.markdown(user_guide_content) | |
| with st.expander("Submit Prediction π"): | |
| user_selection_and_prediction() | |
| with st.expander("Predictions π"): | |
| display_predictions() | |
| with st.expander("Leaderboard π"): | |
| display_leaderboard() | |
| ############################# Admin Panel ################################## | |
| ADMIN_PASSPHRASE = "admin123" | |
| def load_predictions(): | |
| # loading predictions from 'predictions.csv' | |
| try: | |
| return load_data(PREDICTIONS_CSV) | |
| except FileNotFoundError: | |
| return pd.DataFrame(columns=['user_name', 'match_id', 'predicted_winner', 'predicted_motm', 'bid_points']) | |
| def save_users(users): | |
| with open(USERS_JSON, 'w') as file: | |
| json.dump(users, file, indent=4) | |
| def save_match_outcomes(outcomes): | |
| with open(OUTCOMES_JSON, 'w') as file: | |
| json.dump(outcomes, file, indent=4) | |
| def update_leaderboard_and_outcomes(match_id, winning_team, man_of_the_match): | |
| outcomes = load_data(OUTCOMES_JSON) # Load existing match outcomes | |
| predictions = load_predictions() # Load existing predictions | |
| users = load_data(USERS_JSON) # Load existing user points | |
| # Update match outcomes | |
| match_outcome = next((outcome for outcome in outcomes if outcome['match_id'] == match_id), None) | |
| if match_outcome: | |
| match_outcome['winning_team'] = winning_team | |
| match_outcome['man_of_the_match'] = man_of_the_match | |
| else: | |
| outcomes.append({ | |
| "match_id": match_id, | |
| "winning_team": winning_team, | |
| "man_of_the_match": man_of_the_match | |
| }) | |
| # Update user points based on prediction accuracy | |
| match_predictions = predictions[predictions['match_id'] == match_id] | |
| for _, prediction in match_predictions.iterrows(): | |
| user_name = prediction['user_name'] | |
| # Initialize user points if not present | |
| users[user_name] = users.get(user_name, 0) | |
| # Points for correct or incorrect team prediction | |
| if prediction['predicted_winner'] == winning_team: | |
| users[user_name] += 1000 # Correct team prediction | |
| # Check for double or nothing bid points | |
| users[user_name] += prediction['bid_points'] * 2 | |
| else: | |
| users[user_name] -= 200 # Deduct points for incorrect team prediction | |
| users[user_name] -= prediction['bid_points'] # Lose bid points for incorrect prediction | |
| # Points for correct man of the match prediction | |
| if prediction['predicted_motm'] == man_of_the_match: | |
| users[user_name] += 200 # Correct man of the match prediction | |
| # Bonus for getting both right | |
| if prediction['predicted_winner'] == winning_team: | |
| users[user_name] += 200 | |
| # Save updated outcomes and user points | |
| save_match_outcomes(outcomes) | |
| save_users(users) | |
| with st.sidebar: | |
| expander = st.expander("Admin Panel", expanded=False) | |
| admin_pass = expander.text_input("Enter admin passphrase:", type="password", key="admin_pass") | |
| if admin_pass == ADMIN_PASSPHRASE: | |
| expander.success("Authenticated") | |
| matches = get_today_matches() # This function fetches today's matches | |
| # If matches are available, let the admin select one | |
| if matches: | |
| match_selection = expander.selectbox("Select Match", matches, format_func=lambda match: f"{match['teams'][0]} vs {match['teams'][1]}", key="match_selection") | |
| selected_match_id = match_selection['match_id'] | |
| teams = match_selection['teams'] | |
| # Let admin select the winning team | |
| winning_team = expander.selectbox("Winning Team", teams, key="winning_team") | |
| # Fetch and display players for the selected winning team | |
| player_list = load_data(PLAYERS_JSON) | |
| if winning_team in player_list: | |
| players = player_list[winning_team] | |
| man_of_the_match = expander.selectbox("Man of the Match", players, key="man_of_the_match") | |
| else: | |
| players = [] | |
| man_of_the_match = expander.text_input("Man of the Match (Type if not listed)", key="man_of_the_match_fallback") | |
| if expander.button("Submit Match Outcome", key="submit_outcome"): | |
| update_leaderboard_and_outcomes(selected_match_id, winning_team, man_of_the_match) | |
| expander.success("Match outcome submitted and leaderboard updated!") | |
| else: | |
| expander.write("No matches are available for today.") | |
| else: | |
| if admin_pass: # Show error only if something was typed | |
| expander.error("Not authenticated") | |