File size: 6,463 Bytes
a303b0f
 
 
 
 
 
 
 
02817fd
6648256
a303b0f
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
add3bed
4a0d2aa
 
add3bed
 
4a0d2aa
 
 
 
 
 
 
 
 
 
 
 
 
add3bed
a303b0f
4a0d2aa
 
 
 
 
 
add3bed
 
4a0d2aa
 
 
 
add3bed
 
4a0d2aa
a303b0f
add3bed
 
02817fd
 
 
4a0d2aa
add3bed
3e464ec
 
a303b0f
 
 
add3bed
a303b0f
 
 
add3bed
a303b0f
02817fd
4a0d2aa
 
add3bed
 
 
 
 
 
 
 
b2cc102
add3bed
3e464ec
b2cc102
add3bed
 
 
 
4a0d2aa
b2cc102
 
add3bed
 
 
 
 
a303b0f
 
 
 
 
 
 
 
 
 
 
 
 
add3bed
a303b0f
add3bed
a303b0f
 
add3bed
a303b0f
 
 
add3bed
4a0d2aa
add3bed
 
 
 
4a0d2aa
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
import os
import json
import tempfile
from datetime import datetime, timezone
from huggingface_hub import hf_hub_download, upload_file
from huggingface_hub.utils import HfHubHTTPError

# Constant for the dataset repository, configurable via environment variable
DATASET_REPO = os.getenv("HF_DATASET_REPO", "Jofthomas/geoguessr_game_of_the_day")
BLOCK_MULTIPLE_GAMES = os.getenv("Block_Multiple_games", "False") == "true"

def get_todays_records_path() -> str:
    """Gets the path for today's game records file, e.g., 'records/2025-10-03.json'."""
    date_str = datetime.now(timezone.utc).strftime('%Y-%m-%d')
    return f"records/{date_str}.json"

def get_todays_games(token: str) -> list:
    """
    Downloads and reads the game records for the current day from the HF Hub.
    Returns an empty list if the file for today doesn't exist yet.
    """
    filepath = get_todays_records_path()
    try:
        # Use the provided token for read access
        local_path = hf_hub_download(
            repo_id=DATASET_REPO,
            filename=filepath,
            repo_type="dataset",
            token=token,
        )
        with open(local_path, "r", encoding="utf-8") as f:
            return json.load(f)
    except HfHubHTTPError as e:
        if e.response.status_code == 404:
            return []  # No games played today yet, which is normal.
        else:
            print(f"Error downloading daily records: {e}")
            raise  # Re-raise other HTTP errors
    except Exception as e:
        print(f"An unexpected error occurred while getting today's games: {e}")
        return []

def has_user_played_today(username: str, todays_games: list) -> bool:
    """Checks if a user has completed a game today."""
    today_date = datetime.now(timezone.utc).date().isoformat()
    
    for game in todays_games:
        if game.get("username") == username and game.get("completed", False):
            # Additional check: ensure the game's timestamp is from today
            game_timestamp = game.get("timestamp", "")
            if game_timestamp:
                try:
                    game_date = datetime.fromisoformat(game_timestamp.replace('Z', '+00:00')).date().isoformat()
                    if game_date == today_date:
                        return True
                except:
                    # If we can't parse the timestamp, assume it's from today (since it's in todays_games)
                    return True
            else:
                # If no timestamp, assume it's from today (since it's in todays_games)
                return True
    return False

def get_user_game_today(username: str, todays_games: list, game_id: str = None) -> dict:
    """
    Gets the user's game record for today, if it exists.
    If game_id is provided, returns the specific game with that ID.
    Otherwise, returns the first game found for the user.
    """
    for game in todays_games:
        if game.get("username") == username:
            if game_id and game.get("game_id") == game_id:
                return game
            elif not game_id:
                return game
    return None

def update_game_record(username: str, game_id: str, round_data: dict = None, final_score: float = None, final_ai_score: float = None):
    """
    Updates or creates a game record for a user after each round.
    This ensures data is recorded incrementally and prevents abuse.
    
    Args:
        username: The player's username
        game_id: Unique identifier for this game session
        round_data: Single round details to append to the record
        final_score: Final total human score (only set when game is complete)
        final_ai_score: Final total AI score (only set when game is complete)
    """
    write_token = os.getenv("HF_TOKEN", "")
    if not write_token:
        print("Warning: Server HF_TOKEN not set. Cannot record game data.")
        return

    try:
        # Fetch the latest records
        todays_games = get_todays_games(token=write_token)
        
        # Find existing game record for this user today with this specific game_id
        existing_game = get_user_game_today(username, todays_games, game_id)
        
        if existing_game:
            # Update existing record
            if round_data:
                if "rounds" not in existing_game:
                    existing_game["rounds"] = []
                existing_game["rounds"].append(round_data)
            if final_score is not None:
                existing_game["human_score"] = float(round(final_score))
                existing_game["completed"] = True
            if final_ai_score is not None:
                existing_game["ai_score"] = float(round(final_ai_score))
        else:
            # Create new game record
            game_record = {
                "username": username,
                "game_id": game_id,
                "human_score": 0.0,  # Will be updated when game completes
                "ai_score": 0.0,  # Will be updated when game completes
                "timestamp": datetime.now(timezone.utc).isoformat(),
                "rounds": [round_data] if round_data else [],
                "completed": False
            }
            todays_games.append(game_record)

        filepath_in_repo = get_todays_records_path()

        with tempfile.NamedTemporaryFile(mode="w+", delete=False, suffix=".json", encoding="utf-8") as tmp_file:
            json.dump(todays_games, tmp_file, indent=2)
            tmp_file_path = tmp_file.name

        upload_file(
            path_or_fileobj=tmp_file_path,
            path_in_repo=filepath_in_repo,
            repo_id=DATASET_REPO,
            repo_type="dataset",
            token=write_token,
            commit_message=f"Update game for {username}"
        )
        print(f"Successfully updated game record for {username}")

    except Exception as e:
        print(f"Error updating game record for {username}: {e}")
    finally:
        if 'tmp_file_path' in locals() and os.path.exists(tmp_file_path):
            os.remove(tmp_file_path)

def record_game(username: str, score: float, rounds_data: list = None, ai_score: float = None, game_id: str = None):
    """
    Legacy function - now just calls update_game_record with final score.
    Kept for backwards compatibility.
    """
    if not game_id:
        import uuid
        game_id = str(uuid.uuid4())
    update_game_record(username, game_id, final_score=score, final_ai_score=ai_score)