Files changed (1) hide show
  1. app.py +64 -62
app.py CHANGED
@@ -982,27 +982,26 @@ def play_page():
982
  st.session_state['question_started_at'] = time.time()
983
  st.rerun()
984
 
 
985
  # ---------------- SUBMIT ----------------
986
  with col2:
987
  if idx == len(questions) - 1:
988
  if st.button("Submit All Answers", key=f"submit_{gid}_{idx}"):
989
-
990
  answers = st.session_state['answers']
991
  times = st.session_state['answer_times']
992
-
993
  answers[idx] = choice
994
  times[idx] = time.time() - st.session_state['question_started_at']
995
 
996
- # ---------------- FIX 5 : CORRECT SCORING ----------------
997
  score, flags = compute_score(
998
  questions,
999
  answers,
1000
  times
1001
  )
1002
-
1003
  percentage = int(score / (len(questions) * 15) * 100)
1004
-
1005
- # Update players
1006
  players = unified_get("players") or {}
1007
  players.setdefault(gid, {})
1008
  players[gid][uname] = {
@@ -1014,8 +1013,22 @@ def play_page():
1014
  "timestamp": now_iso()
1015
  }
1016
  unified_set("players", players)
1017
-
1018
- # Auto-close game
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1019
  if game.get('auto_close', True):
1020
  games[gid]['closed'] = True
1021
  games[gid]['closed_at'] = now_iso()
@@ -1025,12 +1038,11 @@ def play_page():
1025
  f"Submitted! Score: {score} / {len(questions) * 15} ({percentage}%)"
1026
  )
1027
  st.balloons()
1028
-
1029
  st.session_state['last_score'] = score
1030
  st.session_state['last_game'] = gid
1031
  st.session_state['current_index'] = 0
1032
-
1033
-
1034
  # Join game
1035
  def join_game_page():
1036
  st.header("Join Game")
@@ -1072,12 +1084,8 @@ def join_game_page():
1072
  else:
1073
  st.error(msg)
1074
 
1075
-
1076
-
1077
  # Play page
1078
  # ----------------- Create Game -----------------
1079
-
1080
-
1081
 
1082
  # Friends page
1083
  def friends_page():
@@ -1175,66 +1183,60 @@ def inbox_page():
1175
  st.error(msg)
1176
 
1177
  # Leaderboard page
 
1178
  def leaderboard_page():
1179
- st.header("Leaderboard")
1180
-
1181
- # โœ… Correct source (Online + Offline safe)
1182
- rows = unified_get("/leaderboard") or []
1183
-
1184
- if isinstance(rows, list) and rows:
1185
- df = pd.DataFrame(rows)
1186
- else:
1187
- try:
1188
- df = pd.read_csv(LEADERBOARD_FILE)
1189
- except Exception:
1190
- df = pd.DataFrame()
1191
 
1192
- if df.empty:
1193
- st.info("No scores yet.")
 
1194
  return
1195
 
1196
- # โœ… Ensure numeric score
1197
- if "score" in df.columns:
1198
- df["score"] = pd.to_numeric(df["score"], errors="coerce").fillna(0)
1199
-
1200
- # ๐Ÿ”’ Stable sorting
1201
- sort_cols = ["score"]
1202
- asc = [False]
1203
 
1204
- if "timestamp" in df.columns:
1205
- sort_cols.append("timestamp")
1206
- asc.append(True)
 
1207
 
1208
- df_sorted = df.sort_values(by=sort_cols, ascending=asc)
 
 
 
 
 
1209
 
1210
- # ๐Ÿ”ฅ SUMMARY (NO UI CHANGE)
1211
- total_players = df["name"].nunique() if "name" in df.columns else len(df)
1212
- total_games = df["game_id"].nunique() if "game_id" in df.columns else 1
 
 
 
 
1213
 
1214
- st.markdown(f"**๐Ÿ‘ฅ Total Players:** {total_players}")
1215
- st.markdown(f"**๐ŸŽฎ Total Games:** {total_games}")
1216
 
1217
- # ๐Ÿ”ฅ TOP 3 PODIUM (overall)
1218
- st.markdown("### ๐Ÿ† Top 3 Overall")
1219
- top3 = df_sorted.head(3)
1220
- for _, row in top3.iterrows():
1221
- st.write(
1222
- f"{row.get('avatar','๐ŸŽฎ')} **{row.get('name','Unknown')}** โ€” "
1223
- f"{row.get('score',0)} pts"
1224
- )
1225
 
1226
  st.markdown("---")
1227
 
1228
- # Existing table (unchanged)
1229
- st.dataframe(df_sorted.head(200))
 
 
 
 
 
 
 
 
1230
 
1231
- # Existing chart (unchanged)
1232
- fig = px.bar(
1233
- df_sorted.head(10),
1234
- x="name",
1235
- y="score"
1236
- )
1237
- st.plotly_chart(fig, use_container_width=True)
1238
 
1239
 
1240
 
 
982
  st.session_state['question_started_at'] = time.time()
983
  st.rerun()
984
 
985
+ # ---------------- SUBMIT ----------------
986
  # ---------------- SUBMIT ----------------
987
  with col2:
988
  if idx == len(questions) - 1:
989
  if st.button("Submit All Answers", key=f"submit_{gid}_{idx}"):
 
990
  answers = st.session_state['answers']
991
  times = st.session_state['answer_times']
992
+
993
  answers[idx] = choice
994
  times[idx] = time.time() - st.session_state['question_started_at']
995
 
996
+ # Compute score
997
  score, flags = compute_score(
998
  questions,
999
  answers,
1000
  times
1001
  )
 
1002
  percentage = int(score / (len(questions) * 15) * 100)
1003
+
1004
+ # Update players dict
1005
  players = unified_get("players") or {}
1006
  players.setdefault(gid, {})
1007
  players[gid][uname] = {
 
1013
  "timestamp": now_iso()
1014
  }
1015
  unified_set("players", players)
1016
+ # Push to leaderboard CSV / Firebase
1017
+ row = {
1018
+ "name": uname,
1019
+ "avatar": st.session_state.get("avatar", "๐ŸŽฎ"),
1020
+ "score": score,
1021
+ "percentage": percentage,
1022
+ "game_id": gid,
1023
+ "topics": game.get("topics", []),
1024
+ "timestamp": now_iso(),
1025
+ "questions": len(questions),
1026
+ "answers": answers,
1027
+ "correct_flags": flags
1028
+ }
1029
+ unified_push_leaderboard(row) # <--- THIS IS KEY
1030
+
1031
+ # Auto-close game if needed
1032
  if game.get('auto_close', True):
1033
  games[gid]['closed'] = True
1034
  games[gid]['closed_at'] = now_iso()
 
1038
  f"Submitted! Score: {score} / {len(questions) * 15} ({percentage}%)"
1039
  )
1040
  st.balloons()
 
1041
  st.session_state['last_score'] = score
1042
  st.session_state['last_game'] = gid
1043
  st.session_state['current_index'] = 0
1044
+ st.rerun()
1045
+
1046
  # Join game
1047
  def join_game_page():
1048
  st.header("Join Game")
 
1084
  else:
1085
  st.error(msg)
1086
 
 
 
1087
  # Play page
1088
  # ----------------- Create Game -----------------
 
 
1089
 
1090
  # Friends page
1091
  def friends_page():
 
1183
  st.error(msg)
1184
 
1185
  # Leaderboard page
1186
+ # ----------------- Leaderboard Page -----------------
1187
  def leaderboard_page():
1188
+ st.header("๐Ÿ† Leaderboard")
 
 
 
 
 
 
 
 
 
 
 
1189
 
1190
+ rows = unified_get("leaderboard") or []
1191
+ if not rows:
1192
+ st.info("No scores yet. Play some games first!")
1193
  return
1194
 
1195
+ # Convert to DataFrame
1196
+ df = pd.DataFrame(rows)
 
 
 
 
 
1197
 
1198
+ # Ensure columns exist
1199
+ for col in ["name", "score", "game_id", "avatar", "timestamp"]:
1200
+ if col not in df.columns:
1201
+ df[col] = ""
1202
 
1203
+ # ---------------- Weekly Leaderboard ----------------
1204
+ st.subheader("This Week โ€” Top 10")
1205
+ now = datetime.utcnow()
1206
+ start_of_week = now - timedelta(days=now.weekday())
1207
+ df['ts'] = pd.to_datetime(df['timestamp'], errors='coerce')
1208
+ weekly_df = df[df['ts'] >= start_of_week].copy()
1209
 
1210
+ if weekly_df.empty:
1211
+ st.info("No scores recorded this week.")
1212
+ else:
1213
+ weekly_df = weekly_df.sort_values(by='score', ascending=False).head(10)
1214
+ for i, row in weekly_df.iterrows():
1215
+ user_marker = "๐Ÿ‘ˆ You" if row['name'] == st.session_state.get('username') else ""
1216
+ st.write(f"{i+1}. {row.get('avatar','๐ŸŽฎ')} **{row['name']}** (Game {row['game_id']}) โ€” {row['score']} pts {user_marker}")
1217
 
1218
+ st.markdown("---")
 
1219
 
1220
+ # ---------------- All-time Leaderboard ----------------
1221
+ st.subheader("All-Time Top 10")
1222
+ alltime_df = df.sort_values(by='score', ascending=False).head(10)
1223
+ for i, row in alltime_df.iterrows():
1224
+ user_marker = "๐Ÿ‘ˆ You" if row['name'] == st.session_state.get('username') else ""
1225
+ st.write(f"{i+1}. {row.get('avatar','๐ŸŽฎ')} **{row['name']}** (Game {row['game_id']}) โ€” {row['score']} pts {user_marker}")
 
 
1226
 
1227
  st.markdown("---")
1228
 
1229
+ # Optional: allow search by username
1230
+ search_user = st.text_input("Search leaderboard by username")
1231
+ if search_user:
1232
+ search_df = df[df['name'].str.lower() == search_user.lower()]
1233
+ if search_df.empty:
1234
+ st.info(f"No scores found for {search_user}.")
1235
+ else:
1236
+ st.subheader(f"Scores for {search_user}")
1237
+ for i, row in search_df.iterrows():
1238
+ st.write(f"Game {row['game_id']} โ€” {row['score']} pts โ€” {row.get('avatar','๐ŸŽฎ')} โ€” {row['timestamp']}")
1239
 
 
 
 
 
 
 
 
1240
 
1241
 
1242