Files changed (1) hide show
  1. app.py +70 -63
app.py CHANGED
@@ -651,28 +651,40 @@ def join_game(game_id, username, avatar):
651
 
652
  return ok, msg
653
 
 
 
 
654
 
655
- def compute_score(questions, answers, times):
656
- total = 0
 
 
 
 
 
 
 
 
 
657
  flags = []
658
 
659
- for i, q in enumerate(questions):
660
- ans = answers[i] if i < len(answers) else ""
 
661
 
662
- correct_ans = q.get("answer", "")
 
 
 
 
663
 
664
- correct = str(ans).strip().lower() == str(correct_ans).strip().lower()
 
 
 
665
 
666
- if correct:
667
- base = 10
668
- t = times[i] if i < len(times) and times[i] else 999
669
- bonus = max(0, int((max(0, 15 - min(t, 15)) / 15) * 5))
670
- total += base + bonus
671
- flags.append("Yes")
672
- else:
673
- flags.append("No")
674
 
675
- return total, flags
676
 
677
 
678
  # ----------------- UI -----------------
@@ -904,52 +916,50 @@ def create_game(host=None, topics=[], num_questions=5, auto_close=True, ai_topic
904
 
905
  st.success(f"Game created: {gid} with {len(questions)} questions.")
906
  return gid
907
-
908
-
909
 
910
-
911
  # -------------------------
912
  # PLAY PAGE
913
  # -------------------------
914
  def play_page():
915
  gid = st.session_state.get("active_game_id")
916
  uname = st.session_state.get("username")
917
-
918
  if not gid or not uname:
919
  st.error("No active game or username found. Please join or create a game first.")
920
  return
921
 
 
922
  games = unified_get("games") or {}
923
  game = games.get(gid)
924
  if not game:
925
- st.error("Game not found!")
 
 
 
926
  return
927
 
928
- questions = st.session_state.get("game_questions") or game.get("questions", [])
929
  if not questions:
930
- st.error("No questions loaded.")
931
  return
932
 
933
- # ---------------- FIX 3 : SAFE SESSION INIT ----------------
934
- if 'current_index' not in st.session_state or st.session_state['current_index'] is None:
935
- st.session_state['current_index'] = 0
936
-
937
- if 'answers' not in st.session_state or len(st.session_state['answers']) != len(questions):
938
- st.session_state['answers'] = [""] * len(questions)
939
-
940
- if 'answer_times' not in st.session_state or len(st.session_state['answer_times']) != len(questions):
941
- st.session_state['answer_times'] = [None] * len(questions)
942
 
943
- if 'question_started_at' not in st.session_state or st.session_state['question_started_at'] is None:
944
- st.session_state['question_started_at'] = time.time()
945
-
946
- idx = st.session_state['current_index']
947
 
 
948
  if idx >= len(questions):
949
  st.success("All done — submit your answers!")
950
  return
951
 
952
- # ---------------- QUESTION UI ----------------
953
  q = questions[idx]
954
  st.subheader(f"Question {idx+1}/{len(questions)}")
955
  st.write(q["question"])
@@ -958,49 +968,42 @@ def play_page():
958
  time_limit = 15
959
  st.markdown(f"**Time left:** {max(0, time_limit - elapsed)} seconds")
960
 
961
- # ---------------- FIX 4 : STABLE RADIO ----------------
962
  choice = st.radio(
963
  "Choose an answer:",
964
  q["options"],
 
965
  key=f"choice_{gid}_{idx}"
966
  )
967
 
968
  col1, col2 = st.columns(2)
969
 
970
- # ---------------- NEXT ----------------
971
  with col1:
972
  if st.button("Next", key=f"next_{gid}_{idx}"):
973
- taken = time.time() - st.session_state['question_started_at']
974
-
975
- answers = st.session_state['answers']
976
- times = st.session_state['answer_times']
977
-
978
- answers[idx] = choice
979
- times[idx] = taken
980
-
981
  st.session_state['current_index'] = idx + 1
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, {})
@@ -1013,7 +1016,8 @@ def play_page():
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", "🎮"),
@@ -1026,22 +1030,25 @@ def play_page():
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()
1035
  unified_set("games", games)
1036
 
1037
- st.success(
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():
 
651
 
652
  return ok, msg
653
 
654
+ def compute_score(questions, answers, times=None):
655
+ """
656
+ Compute the total score and correctness flags for each question.
657
 
658
+ Args:
659
+ questions (list): List of question dicts. Each dict must have 'answer' key.
660
+ answers (list): List of user's answers corresponding to questions.
661
+ times (list, optional): Time taken for each question (in seconds).
662
+
663
+ Returns:
664
+ score (int): Total score.
665
+ flags (list): List of correctness flags: True if correct, False if incorrect.
666
+ """
667
+ score_per_question = 15
668
+ score = 0
669
  flags = []
670
 
671
+ for idx, q in enumerate(questions):
672
+ correct_ans = q.get("answer")
673
+ user_ans = answers[idx] if idx < len(answers) else None
674
 
675
+ if user_ans == correct_ans:
676
+ score += score_per_question
677
+ flags.append(True)
678
+ else:
679
+ flags.append(False)
680
 
681
+ # Optional: implement time-based penalties if needed
682
+ # if times:
683
+ # if times[idx] > 15: # example: 15 sec limit
684
+ # score -= 5 # penalty
685
 
686
+ return score, flags
 
 
 
 
 
 
 
687
 
 
688
 
689
 
690
  # ----------------- UI -----------------
 
916
 
917
  st.success(f"Game created: {gid} with {len(questions)} questions.")
918
  return gid
 
 
919
 
 
920
  # -------------------------
921
  # PLAY PAGE
922
  # -------------------------
923
  def play_page():
924
  gid = st.session_state.get("active_game_id")
925
  uname = st.session_state.get("username")
 
926
  if not gid or not uname:
927
  st.error("No active game or username found. Please join or create a game first.")
928
  return
929
 
930
+ # Fetch game and questions
931
  games = unified_get("games") or {}
932
  game = games.get(gid)
933
  if not game:
934
+ st.error("Game not found.")
935
+ return
936
+ if game.get("closed"):
937
+ st.warning("This game has already ended.")
938
  return
939
 
940
+ questions = game.get("questions", [])
941
  if not questions:
942
+ st.info("No questions loaded.")
943
  return
944
 
945
+ # Initialize session state
946
+ if "current_index" not in st.session_state:
947
+ st.session_state["current_index"] = 0
948
+ if "answers" not in st.session_state:
949
+ st.session_state["answers"] = [None] * len(questions)
950
+ if "answer_times" not in st.session_state:
951
+ st.session_state["answer_times"] = [0] * len(questions)
952
+ if "question_started_at" not in st.session_state:
953
+ st.session_state["question_started_at"] = time.time()
954
 
955
+ idx = st.session_state["current_index"]
 
 
 
956
 
957
+ # ---------------- End of questions ----------------
958
  if idx >= len(questions):
959
  st.success("All done — submit your answers!")
960
  return
961
 
962
+ # ---------------- Question UI ----------------
963
  q = questions[idx]
964
  st.subheader(f"Question {idx+1}/{len(questions)}")
965
  st.write(q["question"])
 
968
  time_limit = 15
969
  st.markdown(f"**Time left:** {max(0, time_limit - elapsed)} seconds")
970
 
971
+ # ---------------- Stable Radio ----------------
972
  choice = st.radio(
973
  "Choose an answer:",
974
  q["options"],
975
+ index=st.session_state['answers'][idx] if st.session_state['answers'][idx] in q["options"] else 0,
976
  key=f"choice_{gid}_{idx}"
977
  )
978
 
979
  col1, col2 = st.columns(2)
980
 
981
+ # ---------------- Next Button ----------------
982
  with col1:
983
  if st.button("Next", key=f"next_{gid}_{idx}"):
984
+ # Record answer and time
985
+ st.session_state['answers'][idx] = choice
986
+ st.session_state['answer_times'][idx] = time.time() - st.session_state['question_started_at']
987
+ # Move to next question
 
 
 
 
988
  st.session_state['current_index'] = idx + 1
989
  st.session_state['question_started_at'] = time.time()
990
  st.rerun()
991
 
992
+ # ---------------- Submit Button ----------------
 
993
  with col2:
994
  if idx == len(questions) - 1:
995
  if st.button("Submit All Answers", key=f"submit_{gid}_{idx}"):
996
+ # Record last question
997
+ st.session_state['answers'][idx] = choice
998
+ st.session_state['answer_times'][idx] = time.time() - st.session_state['question_started_at']
999
+
1000
  answers = st.session_state['answers']
1001
  times = st.session_state['answer_times']
 
 
 
1002
 
1003
  # Compute score
1004
+ score, flags = compute_score(questions, answers, times)
 
 
 
 
1005
  percentage = int(score / (len(questions) * 15) * 100)
1006
+
1007
  # Update players dict
1008
  players = unified_get("players") or {}
1009
  players.setdefault(gid, {})
 
1016
  "timestamp": now_iso()
1017
  }
1018
  unified_set("players", players)
1019
+
1020
+ # Push to leaderboard
1021
  row = {
1022
  "name": uname,
1023
  "avatar": st.session_state.get("avatar", "🎮"),
 
1030
  "answers": answers,
1031
  "correct_flags": flags
1032
  }
1033
+ unified_push_leaderboard(row)
1034
+
1035
  # Auto-close game if needed
1036
  if game.get('auto_close', True):
1037
  games[gid]['closed'] = True
1038
  games[gid]['closed_at'] = now_iso()
1039
  unified_set("games", games)
1040
 
1041
+ # Reset session state
1042
+ st.success(f"Submitted! Score: {score} / {len(questions)*15} ({percentage}%)")
 
1043
  st.balloons()
1044
  st.session_state['last_score'] = score
1045
  st.session_state['last_game'] = gid
1046
  st.session_state['current_index'] = 0
1047
+ st.session_state['answers'] = []
1048
+ st.session_state['answer_times'] = []
1049
  st.rerun()
1050
+
1051
+
1052
 
1053
  # Join game
1054
  def join_game_page():