Muthuraja18 commited on
Commit
da0174a
ยท
verified ยท
1 Parent(s): 3d2c2fc
Files changed (1) hide show
  1. app.py +135 -70
app.py CHANGED
@@ -1,6 +1,7 @@
1
  # app.py
2
  """
3
- Fully functional AI Quiz Game โ€” Single Player Only with Chat, Leaderboard & History
 
4
  """
5
 
6
  import os, uuid, time, json, random
@@ -17,62 +18,57 @@ PLAYERS_FILE = os.path.join(DATA_DIR,"players.json")
17
  MESSAGES_FILE = os.path.join(DATA_DIR,"messages.json")
18
  SESSIONS_FILE = os.path.join(DATA_DIR,"sessions.json")
19
  LEADERBOARD_FILE = os.path.join(DATA_DIR,"leaderboard.csv")
 
 
20
 
21
- # ---------------- Questions ----------------
 
 
22
  questions_db = {
23
  "Geography":[("Capital of France?",["Paris","London","Berlin","Madrid"],"Paris"),
24
  ("Largest country by area?",["Canada","USA","Russia","China"],"Russia")],
25
  "Math":[("5*12?",["50","60","55","70"],"60"),
26
- ("sqrt(64)?",["6","7","8","9"],"8")]
 
 
27
  }
28
 
29
  # ---------------- Helpers ----------------
30
- def load_json(path, default):
31
- if os.path.exists(path):
32
- try:
33
- with open(path,"r",encoding="utf-8") as f:
34
- return json.load(f)
35
- except:
36
- return default
37
- return default
38
- def save_json(path,data):
39
- with open(path,"w",encoding="utf-8") as f:
40
- json.dump(data,f,indent=2,ensure_ascii=False)
41
-
42
  def now_iso(): return datetime.utcnow().isoformat()
43
  def parse_iso(s):
44
  try: return datetime.fromisoformat(s)
45
  except: return None
46
 
47
- # ---------------- Initialize ----------------
48
- for f in [GAMES_FILE,PLAYERS_FILE,MESSAGES_FILE,SESSIONS_FILE]:
49
- if not os.path.exists(f): save_json(f,{})
50
-
51
- if not os.path.exists(LEADERBOARD_FILE):
52
- pd.DataFrame(columns=['name','score','game_id','topics','timestamp','avatar']).to_csv(LEADERBOARD_FILE,index=False)
53
-
54
- if "uid" not in st.session_state: st.session_state['uid']=str(uuid.uuid4())
55
- if "session_id" not in st.session_state: st.session_state['session_id']=str(uuid.uuid4())
56
 
57
- # ---------------- Load Data ----------------
58
- def get_data(file): return load_json(file,{})
59
- def set_data(file,data): save_json(file,data)
60
 
61
  def unified_get(collection):
62
- if collection=="games": return get_data(GAMES_FILE)
63
- if collection=="players": return get_data(PLAYERS_FILE)
64
- if collection=="messages": return get_data(MESSAGES_FILE)
65
- if collection=="sessions": return get_data(SESSIONS_FILE)
 
 
66
  if collection=="leaderboard":
67
  try: return pd.read_csv(LEADERBOARD_FILE).to_dict(orient="records")
68
  except: return []
69
  return {}
70
 
71
  def unified_set(collection,data):
72
- if collection=="games": set_data(GAMES_FILE,data)
73
- if collection=="players": set_data(PLAYERS_FILE,data)
74
- if collection=="messages": set_data(MESSAGES_FILE,data)
75
- if collection=="sessions": set_data(SESSIONS_FILE,data)
 
 
76
  if collection=="leaderboard":
77
  pd.DataFrame(data).to_csv(LEADERBOARD_FILE,index=False)
78
 
@@ -85,12 +81,11 @@ def unified_push_message(game_id,msg_obj):
85
  unified_set("messages",all_msgs)
86
 
87
  def unified_push_leaderboard(row):
88
- df = pd.read_csv(LEADERBOARD_FILE)
89
  df = pd.concat([df,pd.DataFrame([row])],ignore_index=True)
90
- df.to_csv(LEADERBOARD_FILE,index=False)
91
 
92
  # ---------------- Session ----------------
93
- HEARTBEAT_THRESHOLD_SECONDS=40
94
  def claim_session(game_id,username):
95
  sessions=unified_get("sessions") or {}
96
  game_sessions=sessions.get(game_id,{})
@@ -157,15 +152,48 @@ def compute_score(questions,answers,times):
157
  total+=base+bonus
158
  return total
159
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
160
  # ---------------- UI ----------------
161
- st.title("AI Quiz Game โ€” Single Player Only")
 
 
 
162
 
 
163
  if "username" not in st.session_state:
164
  st.session_state['username']=st.text_input("Enter your name","Player1")
165
  if "avatar" not in st.session_state:
166
  st.session_state['avatar']=st.selectbox("Choose avatar",["๐ŸŽฎ","๐Ÿฑ","๐Ÿถ","๐Ÿฆ„","๐Ÿ‘ฝ","๐ŸŽฉ"])
167
 
168
- page=st.sidebar.selectbox("Page",["Home","Create Game","Join Game","Play","Leaderboard"],0)
169
 
170
  # ---------------- Home ----------------
171
  if page=="Home":
@@ -185,7 +213,6 @@ elif page=="Create Game":
185
  if st.button("Create Game"):
186
  gid=create_game(st.session_state['username'],topics,num_q)
187
  st.success(f"Game created! Game ID: {gid}")
188
- st.experimental_rerun()
189
 
190
  # ---------------- Join Game ----------------
191
  elif page=="Join Game":
@@ -194,12 +221,9 @@ elif page=="Join Game":
194
  ok,msg=join_game(gid,st.session_state['username'],st.session_state['avatar'])
195
  if ok: st.success(f"Joined Game {gid} successfully!")
196
  else: st.error(msg)
197
- st.experimental_rerun()
198
 
199
  # ---------------- Play ----------------
200
  elif page=="Play":
201
- st.markdown("---")
202
- st.write("Offline mode stores data in ./data/")
203
  gid = st.text_input("Enter Game ID to Play")
204
  if gid:
205
  games = unified_get("games")
@@ -210,6 +234,7 @@ elif page=="Play":
210
  game = games[gid]
211
  username = st.session_state['username']
212
  avatar = st.session_state['avatar']
 
213
  # Join if not joined
214
  if gid not in players or username not in players[gid]:
215
  ok,msg=join_game(gid,username,avatar)
@@ -217,9 +242,15 @@ elif page=="Play":
217
  # Claim session
218
  ok,msg=claim_session(gid,username)
219
  if not ok: st.warning(msg)
220
-
221
  st.subheader(f"Game {gid} โ€” Topics: {', '.join(game['topics'])}")
222
-
 
 
 
 
 
 
223
  # Initialize session variables
224
  if 'play_index' not in st.session_state or st.session_state.get('current_gid')!=gid:
225
  st.session_state['play_index']=0
@@ -227,19 +258,19 @@ elif page=="Play":
227
  st.session_state['times']=[]
228
  st.session_state['start_time']=time.time()
229
  st.session_state['current_gid']=gid
230
-
231
  questions = game['questions']
232
  qidx = st.session_state['play_index']
233
-
234
  if qidx < len(questions):
235
  q = questions[qidx]
236
  st.write(f"Question {qidx+1}: {q[0]}")
237
  ans = st.radio("Select Answer", q[1], key=f"ans{qidx}")
238
-
239
  # Timer
240
  elapsed = int(time.time() - st.session_state['start_time'])
241
  st.write(f"Time elapsed: {elapsed} sec")
242
-
243
  if st.button("Submit Answer"):
244
  st.session_state['answers'].append(ans)
245
  st.session_state['times'].append(elapsed)
@@ -247,50 +278,84 @@ elif page=="Play":
247
  st.session_state['start_time']=time.time()
248
  st.experimental_rerun()
249
  else:
250
- # Game finished
251
  total_score = compute_score(questions, st.session_state['answers'], st.session_state['times'])
252
  st.success(f"Game Finished! Your score: {total_score}")
253
-
254
  # Update leaderboard
255
  row={"name":username,"score":total_score,"game_id":gid,"topics":",".join(game['topics']),
256
  "timestamp":now_iso(),"avatar":avatar}
257
  unified_push_leaderboard(row)
258
-
259
  # Mark submitted
260
  players[gid][username]['submitted']=True
261
  unified_set("players",players)
262
-
263
  st.write("Correct Answers:")
264
  for i,q in enumerate(questions):
265
  st.write(f"Q{i+1}: {q[0]} โ€” Correct: {q[2]} โ€” Your Answer: {st.session_state['answers'][i]}")
266
-
267
  # Reset session variables
268
  del st.session_state['play_index']
269
  del st.session_state['answers']
270
  del st.session_state['times']
271
  del st.session_state['current_gid']
272
  del st.session_state['start_time']
273
-
274
- # ---------------- Chat ----------------
275
- st.markdown("---")
276
- st.subheader("Game Chat")
277
- msg_text = st.text_input("Type a message","",key="chat_input")
278
- if st.button("Send Message"):
279
- if msg_text.strip():
280
- unified_push_message(gid,{"from":username,"avatar":avatar,"msg":msg_text,"ts":now_iso()})
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  st.experimental_rerun()
282
-
283
- msgs = unified_get("messages").get(gid,[])
284
- for m in msgs[-20:]:
285
- st.write(f"{m['avatar']} **{m['from']}**: {m['msg']}")
 
 
 
 
 
 
 
 
 
286
 
287
  # ---------------- Leaderboard ----------------
288
  elif page=="Leaderboard":
289
- st.markdown("---")
290
- st.write("Offline mode stores data in ./data/")
291
- df=pd.read_csv(LEADERBOARD_FILE)
292
  st.subheader("Global Leaderboard")
293
  if not df.empty:
294
  df['display']=df['avatar']+" "+df['name']+" - "+df['score'].astype(str)
295
  st.write(df.sort_values("score",ascending=False)[['display']].head(20))
296
  else: st.write("No scores yet.")
 
 
 
 
1
  # app.py
2
  """
3
+ AI Quiz Game โ€” Online & Offline
4
+ Multiplayer, Chat, Friends, Leaderboard
5
  """
6
 
7
  import os, uuid, time, json, random
 
18
  MESSAGES_FILE = os.path.join(DATA_DIR,"messages.json")
19
  SESSIONS_FILE = os.path.join(DATA_DIR,"sessions.json")
20
  LEADERBOARD_FILE = os.path.join(DATA_DIR,"leaderboard.csv")
21
+ FRIENDS_FILE = os.path.join(DATA_DIR,"friends.json")
22
+ INBOX_FILE = os.path.join(DATA_DIR,"inbox.json")
23
 
24
+ HEARTBEAT_THRESHOLD_SECONDS=40
25
+
26
+ # ---------------- Questions DB ----------------
27
  questions_db = {
28
  "Geography":[("Capital of France?",["Paris","London","Berlin","Madrid"],"Paris"),
29
  ("Largest country by area?",["Canada","USA","Russia","China"],"Russia")],
30
  "Math":[("5*12?",["50","60","55","70"],"60"),
31
+ ("sqrt(64)?",["6","7","8","9"],"8")],
32
+ "Science":[("Water formula?",["H2O","CO2","O2","NaCl"],"H2O"),
33
+ ("Planet closest to Sun?",["Venus","Earth","Mercury","Mars"],"Mercury")]
34
  }
35
 
36
  # ---------------- Helpers ----------------
 
 
 
 
 
 
 
 
 
 
 
 
37
  def now_iso(): return datetime.utcnow().isoformat()
38
  def parse_iso(s):
39
  try: return datetime.fromisoformat(s)
40
  except: return None
41
 
42
+ def load_json(path, default={}):
43
+ if os.path.exists(path):
44
+ try:
45
+ with open(path,"r",encoding="utf-8") as f: return json.load(f)
46
+ except: return default
47
+ return default
 
 
 
48
 
49
+ def save_json(path,data):
50
+ with open(path,"w",encoding="utf-8") as f:
51
+ json.dump(data,f,indent=2,ensure_ascii=False)
52
 
53
  def unified_get(collection):
54
+ if collection=="games": return load_json(GAMES_FILE,{})
55
+ if collection=="players": return load_json(PLAYERS_FILE,{})
56
+ if collection=="messages": return load_json(MESSAGES_FILE,{})
57
+ if collection=="sessions": return load_json(SESSIONS_FILE,{})
58
+ if collection=="friends": return load_json(FRIENDS_FILE,{})
59
+ if collection=="inbox": return load_json(INBOX_FILE,{})
60
  if collection=="leaderboard":
61
  try: return pd.read_csv(LEADERBOARD_FILE).to_dict(orient="records")
62
  except: return []
63
  return {}
64
 
65
  def unified_set(collection,data):
66
+ if collection=="games": save_json(GAMES_FILE,data)
67
+ if collection=="players": save_json(PLAYERS_FILE,data)
68
+ if collection=="messages": save_json(MESSAGES_FILE,data)
69
+ if collection=="sessions": save_json(SESSIONS_FILE,data)
70
+ if collection=="friends": save_json(FRIENDS_FILE,data)
71
+ if collection=="inbox": save_json(INBOX_FILE,data)
72
  if collection=="leaderboard":
73
  pd.DataFrame(data).to_csv(LEADERBOARD_FILE,index=False)
74
 
 
81
  unified_set("messages",all_msgs)
82
 
83
  def unified_push_leaderboard(row):
84
+ df = pd.DataFrame(unified_get("leaderboard"))
85
  df = pd.concat([df,pd.DataFrame([row])],ignore_index=True)
86
+ unified_set("leaderboard",df.to_dict(orient="records"))
87
 
88
  # ---------------- Session ----------------
 
89
  def claim_session(game_id,username):
90
  sessions=unified_get("sessions") or {}
91
  game_sessions=sessions.get(game_id,{})
 
152
  total+=base+bonus
153
  return total
154
 
155
+ # ---------------- Friends ----------------
156
+ def get_friends(): return unified_get("friends") or {}
157
+ def save_friends(f): unified_set("friends",f)
158
+ def get_inbox(): return unified_get("inbox") or {}
159
+ def save_inbox(i): unified_set("inbox",i)
160
+ def send_friend_request(frm,to):
161
+ inbox=get_inbox()
162
+ inbox.setdefault(to,[]).append({"type":"friend_request","from":frm,"ts":now_iso()})
163
+ save_inbox(inbox)
164
+ def accept_friend_request(user,frm):
165
+ friends=get_friends()
166
+ friends.setdefault(user,[]); friends.setdefault(frm,[])
167
+ if frm not in friends[user]: friends[user].append(frm)
168
+ if user not in friends[frm]: friends[frm].append(user)
169
+ save_friends(friends)
170
+ inbox=get_inbox()
171
+ inbox[user]=[e for e in inbox.get(user,[]) if not (e.get("type")=="friend_request" and e.get("from")==frm)]
172
+ save_inbox(inbox)
173
+
174
+ # ---------------- Initialize ----------------
175
+ for f in [GAMES_FILE,PLAYERS_FILE,MESSAGES_FILE,SESSIONS_FILE,FRIENDS_FILE,INBOX_FILE]:
176
+ if not os.path.exists(f): save_json(f,{})
177
+
178
+ if not os.path.exists(LEADERBOARD_FILE):
179
+ pd.DataFrame(columns=['name','score','game_id','topics','timestamp','avatar']).to_csv(LEADERBOARD_FILE,index=False)
180
+
181
+ if "uid" not in st.session_state: st.session_state['uid']=str(uuid.uuid4())
182
+ if "session_id" not in st.session_state: st.session_state['session_id']=str(uuid.uuid4())
183
+
184
  # ---------------- UI ----------------
185
+ st.title("๐ŸŽฏ AI Quiz Game โ€” Online & Offline Multiplayer")
186
+
187
+ # Mode selection
188
+ mode = st.sidebar.selectbox("Select Mode",["Online","Offline"],0)
189
 
190
+ # Player info
191
  if "username" not in st.session_state:
192
  st.session_state['username']=st.text_input("Enter your name","Player1")
193
  if "avatar" not in st.session_state:
194
  st.session_state['avatar']=st.selectbox("Choose avatar",["๐ŸŽฎ","๐Ÿฑ","๐Ÿถ","๐Ÿฆ„","๐Ÿ‘ฝ","๐ŸŽฉ"])
195
 
196
+ page=st.sidebar.selectbox("Page",["Home","Create Game","Join Game","Play","Friends","Inbox","Leaderboard"],0)
197
 
198
  # ---------------- Home ----------------
199
  if page=="Home":
 
213
  if st.button("Create Game"):
214
  gid=create_game(st.session_state['username'],topics,num_q)
215
  st.success(f"Game created! Game ID: {gid}")
 
216
 
217
  # ---------------- Join Game ----------------
218
  elif page=="Join Game":
 
221
  ok,msg=join_game(gid,st.session_state['username'],st.session_state['avatar'])
222
  if ok: st.success(f"Joined Game {gid} successfully!")
223
  else: st.error(msg)
 
224
 
225
  # ---------------- Play ----------------
226
  elif page=="Play":
 
 
227
  gid = st.text_input("Enter Game ID to Play")
228
  if gid:
229
  games = unified_get("games")
 
234
  game = games[gid]
235
  username = st.session_state['username']
236
  avatar = st.session_state['avatar']
237
+
238
  # Join if not joined
239
  if gid not in players or username not in players[gid]:
240
  ok,msg=join_game(gid,username,avatar)
 
242
  # Claim session
243
  ok,msg=claim_session(gid,username)
244
  if not ok: st.warning(msg)
245
+
246
  st.subheader(f"Game {gid} โ€” Topics: {', '.join(game['topics'])}")
247
+
248
+ # Offline graphics difference
249
+ if mode=="Offline":
250
+ st.markdown("### ๐ŸŽฎ Offline Mode โ€” Local Play")
251
+ else:
252
+ st.markdown("### ๐ŸŒ Online Mode โ€” Interactive Multiplayer")
253
+
254
  # Initialize session variables
255
  if 'play_index' not in st.session_state or st.session_state.get('current_gid')!=gid:
256
  st.session_state['play_index']=0
 
258
  st.session_state['times']=[]
259
  st.session_state['start_time']=time.time()
260
  st.session_state['current_gid']=gid
261
+
262
  questions = game['questions']
263
  qidx = st.session_state['play_index']
264
+
265
  if qidx < len(questions):
266
  q = questions[qidx]
267
  st.write(f"Question {qidx+1}: {q[0]}")
268
  ans = st.radio("Select Answer", q[1], key=f"ans{qidx}")
269
+
270
  # Timer
271
  elapsed = int(time.time() - st.session_state['start_time'])
272
  st.write(f"Time elapsed: {elapsed} sec")
273
+
274
  if st.button("Submit Answer"):
275
  st.session_state['answers'].append(ans)
276
  st.session_state['times'].append(elapsed)
 
278
  st.session_state['start_time']=time.time()
279
  st.experimental_rerun()
280
  else:
 
281
  total_score = compute_score(questions, st.session_state['answers'], st.session_state['times'])
282
  st.success(f"Game Finished! Your score: {total_score}")
283
+
284
  # Update leaderboard
285
  row={"name":username,"score":total_score,"game_id":gid,"topics":",".join(game['topics']),
286
  "timestamp":now_iso(),"avatar":avatar}
287
  unified_push_leaderboard(row)
288
+
289
  # Mark submitted
290
  players[gid][username]['submitted']=True
291
  unified_set("players",players)
292
+
293
  st.write("Correct Answers:")
294
  for i,q in enumerate(questions):
295
  st.write(f"Q{i+1}: {q[0]} โ€” Correct: {q[2]} โ€” Your Answer: {st.session_state['answers'][i]}")
296
+
297
  # Reset session variables
298
  del st.session_state['play_index']
299
  del st.session_state['answers']
300
  del st.session_state['times']
301
  del st.session_state['current_gid']
302
  del st.session_state['start_time']
303
+
304
+ # ---------------- Chat (Only Online) ----------------
305
+ if mode=="Online":
306
+ st.markdown("---")
307
+ st.subheader("Game Chat")
308
+ msg_text = st.text_input("Type a message","",key="chat_input")
309
+ if st.button("Send Message"):
310
+ if msg_text.strip():
311
+ unified_push_message(gid,{"from":username,"avatar":avatar,"msg":msg_text,"ts":now_iso()})
312
+ st.experimental_rerun()
313
+
314
+ msgs = unified_get("messages").get(gid,[])
315
+ for m in msgs[-20:]:
316
+ st.write(f"{m['avatar']} **{m['from']}**: {m['msg']}")
317
+
318
+ # ---------------- Friends ----------------
319
+ elif page=="Friends":
320
+ if mode=="Online":
321
+ friends=get_friends()
322
+ inbox=get_inbox()
323
+ st.subheader("Friends")
324
+ myfriends=friends.get(st.session_state['username'],[])
325
+ st.write(myfriends)
326
+ newfriend=st.text_input("Add Friend")
327
+ if st.button("Send Friend Request"):
328
+ if newfriend: send_friend_request(st.session_state['username'],newfriend)
329
+ st.subheader("Inbox")
330
+ user_inbox=inbox.get(st.session_state['username'],[])
331
+ for msg in user_inbox:
332
+ if msg['type']=="friend_request":
333
+ st.write(f"Friend request from {msg['from']}")
334
+ if st.button(f"Accept {msg['from']}"):
335
+ accept_friend_request(st.session_state['username'],msg['from'])
336
  st.experimental_rerun()
337
+ else:
338
+ st.info("Friends feature is only available in Online Mode.")
339
+
340
+ # ---------------- Inbox ----------------
341
+ elif page=="Inbox":
342
+ if mode=="Online":
343
+ inbox=get_inbox()
344
+ user_inbox=inbox.get(st.session_state['username'],[])
345
+ st.subheader("Inbox Messages")
346
+ for msg in user_inbox:
347
+ st.write(msg)
348
+ else:
349
+ st.info("Inbox is only available in Online Mode.")
350
 
351
  # ---------------- Leaderboard ----------------
352
  elif page=="Leaderboard":
353
+ df=pd.DataFrame(unified_get("leaderboard"))
 
 
354
  st.subheader("Global Leaderboard")
355
  if not df.empty:
356
  df['display']=df['avatar']+" "+df['name']+" - "+df['score'].astype(str)
357
  st.write(df.sort_values("score",ascending=False)[['display']].head(20))
358
  else: st.write("No scores yet.")
359
+
360
+ st.markdown("---")
361
+ st.write("Data stored in ./data/. Online mode is interactive; Offline mode is local only.")