sunbal7 commited on
Commit
7b7a20e
·
verified ·
1 Parent(s): 3ad50b9

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +383 -110
app.py CHANGED
@@ -1,16 +1,18 @@
1
- # app.py - Fixed Version with Free Models
2
  import streamlit as st
3
  import os
4
  import time
5
  import random
6
  import json
 
7
  import base64
8
  import requests
9
- import re
10
  from PIL import Image
11
  import io
12
  import matplotlib.pyplot as plt
13
- from transformers import pipeline, set_seed
 
 
14
 
15
  # Configure Streamlit page
16
  st.set_page_config(
@@ -20,23 +22,23 @@ st.set_page_config(
20
  initial_sidebar_state="expanded"
21
  )
22
 
23
- # Custom CSS for game-themed UI
24
  st.markdown("""
25
  <style>
26
  @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Comic+Neue:wght@700&display=swap');
27
 
28
  :root {
29
- --primary: #FF6B6B;
30
- --secondary: #4ECDC4;
31
- --accent: #FFD166;
32
- --dark: #1A535C;
33
- --light: #F7FFF7;
34
- --game-blue: #118AB2;
35
  --game-purple: #9B5DE5;
36
  }
37
 
38
  body {
39
- background: linear-gradient(135deg, #E8F4F8 0%, #FFDEE9 100%);
40
  font-family: 'Comic Neue', cursive;
41
  }
42
 
@@ -48,15 +50,15 @@ st.markdown("""
48
  background-color: white;
49
  border-radius: 20px;
50
  padding: 25px;
51
- box-shadow: 0 8px 32px rgba(26, 83, 92, 0.2);
52
- border: 4px solid var(--game-purple);
53
  margin-bottom: 25px;
54
  transition: all 0.3s;
55
  }
56
 
57
  .game-card:hover {
58
  transform: translateY(-5px);
59
- box-shadow: 0 12px 24px rgba(26, 83, 92, 0.3);
60
  }
61
 
62
  .header {
@@ -66,21 +68,21 @@ st.markdown("""
66
  }
67
 
68
  .concept-card {
69
- background: linear-gradient(145deg, #ffffff, #f0f0f0);
70
  border-radius: 15px;
71
  padding: 15px;
72
  margin: 10px 0;
73
- border-left: 5px solid var(--secondary);
74
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
75
  }
76
 
77
  .stButton>button {
78
- background: linear-gradient(45deg, var(--game-purple), var(--game-blue));
79
  color: white;
80
  border-radius: 50px;
81
  padding: 12px 28px;
82
  font-weight: bold;
83
- font-size: 20px;
84
  border: none;
85
  transition: all 0.3s;
86
  font-family: 'Fredoka One', cursive;
@@ -88,7 +90,7 @@ st.markdown("""
88
 
89
  .stButton>button:hover {
90
  transform: scale(1.05);
91
- box-shadow: 0 8px 16px rgba(0,0,0,0.2);
92
  }
93
 
94
  .stTextInput>div>div>input {
@@ -110,27 +112,28 @@ st.markdown("""
110
 
111
  .tab {
112
  padding: 12px 24px;
113
- background-color: var(--accent);
114
  border-radius: 15px;
115
  cursor: pointer;
116
  font-weight: bold;
117
  white-space: nowrap;
118
  font-family: 'Fredoka One', cursive;
119
- font-size: 18px;
120
  transition: all 0.3s;
 
121
  }
122
 
123
  .tab.active {
124
- background: linear-gradient(45deg, var(--game-purple), var(--game-blue));
125
  color: white;
126
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
127
  }
128
 
129
  .game-preview {
130
- border: 4px solid var(--game-blue);
131
  border-radius: 20px;
132
  overflow: hidden;
133
- background: linear-gradient(135deg, #a2d2ff, #bde0fe);
134
  padding: 20px;
135
  margin: 20px 0;
136
  }
@@ -168,13 +171,69 @@ st.markdown("""
168
 
169
  .game-title {
170
  font-family: 'Fredoka One', cursive;
171
- color: var(--game-purple);
172
  text-align: center;
173
  font-size: 32px;
174
  margin-bottom: 20px;
175
  text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
176
  }
177
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
178
  @media (max-width: 768px) {
179
  .tabs {
180
  flex-wrap: wrap;
@@ -183,6 +242,12 @@ st.markdown("""
183
  .character {
184
  font-size: 48px;
185
  }
 
 
 
 
 
 
186
  }
187
  </style>
188
  """, unsafe_allow_html=True)
@@ -205,6 +270,18 @@ def init_session_state():
205
  st.session_state.active_tab = "story"
206
  if 'loading' not in st.session_state:
207
  st.session_state.loading = False
 
 
 
 
 
 
 
 
 
 
 
 
208
 
209
  # Concept database
210
  CONCEPTS = {
@@ -212,50 +289,50 @@ CONCEPTS = {
212
  "name": "Loop",
213
  "emoji": "🔄",
214
  "description": "Loops repeat actions multiple times",
215
- "example": "for i in range(5):\n print('Hello!')",
216
- "color": "#FF9E6D",
217
- "game_example": "Repeating a jump 5 times to cross a river"
218
  },
219
  "conditional": {
220
  "name": "Conditional",
221
  "emoji": "❓",
222
  "description": "Conditionals make decisions in code",
223
- "example": "if sunny:\n go_outside()\nelse:\n stay_inside()",
224
- "color": "#4ECDC4",
225
- "game_example": "Choosing different paths based on obstacles"
226
  },
227
  "function": {
228
  "name": "Function",
229
  "emoji": "✨",
230
  "description": "Functions are reusable blocks of code",
231
- "example": "def greet(name):\n print(f'Hello {name}!')",
232
- "color": "#FFD166",
233
  "game_example": "Creating a jump function used multiple times"
234
  },
235
  "variable": {
236
  "name": "Variable",
237
  "emoji": "📦",
238
  "description": "Variables store information",
239
- "example": "score = 10\nplayer = 'Alex'",
240
- "color": "#FF6B6B",
241
- "game_example": "Keeping track of collected stars"
242
  },
243
  "list": {
244
  "name": "List",
245
  "emoji": "📝",
246
  "description": "Lists store collections of items",
247
- "example": "fruits = ['apple', 'banana', 'orange']",
248
- "color": "#1A535C",
249
- "game_example": "Storing collected treasures in a backpack"
250
  }
251
  }
252
 
253
- # Load text generation model
254
- @st.cache_resource(show_spinner=False)
255
- def load_text_generator():
256
- """Load a lightweight text generation model"""
257
  try:
258
- return pipeline('text-generation', model='gpt2', framework='pt', device=-1)
 
 
259
  except:
260
  return None
261
 
@@ -265,47 +342,80 @@ def analyze_story(story):
265
  story_lower = story.lower()
266
  detected_concepts = []
267
 
 
268
  # Check for loops
269
- if any(word in story_lower for word in ["times", "repeat", "again", "multiple"]):
270
  detected_concepts.append("loop")
271
 
272
  # Check for conditionals
273
- if any(word in story_lower for word in ["if", "when", "unless", "whether", "decide"]):
274
  detected_concepts.append("conditional")
275
 
276
  # Check for functions
277
- if any(word in story_lower for word in ["make", "create", "do", "perform", "cast"]):
278
  detected_concepts.append("function")
279
 
280
  # Check for variables
281
- if any(word in story_lower for word in ["is", "has", "set to", "value", "score"]):
282
  detected_concepts.append("variable")
283
 
284
  # Check for lists
285
- if any(word in story_lower for word in ["and", "many", "several", "collection", "items"]):
286
  detected_concepts.append("list")
287
 
288
- return list(set(detected_concepts))
289
 
290
- # Generate game scenario using free models
291
  def generate_game_scenario(story, concepts):
292
  """Generate a game scenario based on the story and concepts"""
293
- # Create a simple template-based scenario
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
294
  concept_names = [CONCEPTS[c]['name'] for c in concepts]
295
  concept_list = ", ".join(concept_names)
296
-
297
  return f"""
298
  Game Title: {story[:15]} Adventure
299
- Game Objective: Complete challenges based on the story: {story[:100]}...
300
  Characters:
301
  - Hero: The main character from your story
302
  - Helper: A friendly guide who explains coding concepts
303
  - Villain: A character that creates obstacles (if applicable)
304
 
305
  Game Mechanics:
306
- 1. The player controls the hero using arrow keys
307
- 2. Collect items mentioned in the story
308
- 3. Avoid obstacles and solve simple puzzles
309
  4. Helper characters appear to teach {concept_list}
310
 
311
  Coding Concepts: This game teaches {concept_list} through:
@@ -321,7 +431,37 @@ Visual Description: Colorful 3D world with cartoon-style characters, vibrant lan
321
  # Generate game code explanation
322
  def generate_game_explanation(story, concepts, game_scenario):
323
  """Generate explanation of game code"""
324
- # Create simple explanation based on concepts
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  concept_explanations = "\n".join(
326
  [f"- {CONCEPTS[c]['name']}: {CONCEPTS[c]['game_example']}" for c in concepts]
327
  )
@@ -340,14 +480,19 @@ The code brings your story to life in a 3D game world!
340
  # Generate simple game code
341
  def generate_game_code(story, concepts):
342
  """Generate simple PyGame code for the game"""
343
- # Generate a unique game based on story keywords
344
  keywords = re.findall(r'\b\w{4,}\b', story)[:3]
345
- player_char = keywords[0] if keywords else "hero"
346
  collect_item = keywords[1] if len(keywords) > 1 else "star"
347
  obstacle = keywords[2] if len(keywords) > 2 else "rock"
348
 
 
 
 
349
  return f"""
350
- # {story[:30]} Adventure Game
 
 
351
  import pygame
352
  import random
353
  import sys
@@ -358,24 +503,24 @@ pygame.init()
358
  # Game setup
359
  WIDTH, HEIGHT = 800, 600
360
  screen = pygame.display.set_mode((WIDTH, HEIGHT))
361
- pygame.display.set_caption("{player_char.capitalize()} Adventure")
362
  clock = pygame.time.Clock()
363
 
364
  # Colors
365
- BACKGROUND = (173, 216, 230) # Light blue
366
- PLAYER_COLOR = (255, 0, 0) # Red
367
- GOAL_COLOR = (255, 223, 0) # Gold
368
- OBSTACLE_COLOR = (139, 69, 19) # Brown
369
- TEXT_COLOR = (0, 0, 0) # Black
370
 
371
  # Player setup
372
- player_size = 50
373
  player_x = 100
374
  player_y = HEIGHT // 2
375
  player_speed = 5
376
 
377
  # Goal setup
378
- goal_size = 40
379
  goal_x = WIDTH - 150
380
  goal_y = HEIGHT // 2
381
 
@@ -389,7 +534,7 @@ for i in range(5):
389
  obstacles.append([
390
  random.randint(200, WIDTH - 100),
391
  random.randint(50, HEIGHT - 100),
392
- random.randint(20, 50),
393
  random.randint(20, 50)
394
  ])
395
 
@@ -403,13 +548,13 @@ while running:
403
 
404
  # Player movement
405
  keys = pygame.key.get_pressed()
406
- if keys[pygame.K_UP]:
407
  player_y -= player_speed
408
- if keys[pygame.K_DOWN]:
409
  player_y += player_speed
410
- if keys[pygame.K_LEFT]:
411
  player_x -= player_speed
412
- if keys[pygame.K_RIGHT]:
413
  player_x += player_speed
414
 
415
  # Boundary checking
@@ -439,20 +584,24 @@ while running:
439
  # Draw player and goal
440
  pygame.draw.rect(screen, PLAYER_COLOR,
441
  (player_x, player_y, player_size, player_size))
442
- pygame.draw.rect(screen, GOAL_COLOR,
443
- (goal_x, goal_y, goal_size, goal_size))
444
 
445
  # Display score
446
  score_text = font.render(f"{collect_item.capitalize()}s: {{score}}", True, TEXT_COLOR)
447
  screen.blit(score_text, (20, 20))
448
 
449
  # Display story title
450
- title_text = font.render(f"{player_char.capitalize()} Adventure", True, TEXT_COLOR)
451
- screen.blit(title_text, (WIDTH // 2 - 100, 20))
 
 
 
 
452
 
453
  # Display instructions
454
- help_text = font.render("Arrow keys to move - Collect the gold squares!", True, TEXT_COLOR)
455
- screen.blit(help_text, (WIDTH // 2 - 200, HEIGHT - 40))
456
 
457
  # Update display
458
  pygame.display.flip()
@@ -463,55 +612,170 @@ sys.exit()
463
  """
464
 
465
  # Generate game preview visualization
466
- def generate_game_preview():
467
  """Generate a visual preview of the game"""
468
  try:
 
 
 
469
  # Create a simple visualization
470
  fig, ax = plt.subplots(figsize=(10, 6))
471
- ax.set_facecolor('#a2d2ff')
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
472
  ax.set_xlim(0, 10)
473
  ax.set_ylim(0, 6)
474
 
475
  # Draw game elements
476
- ax.text(5, 5, "Your Adventure", fontsize=20, ha='center', color='#9b5de5')
477
- ax.plot([1, 9], [3, 3], 'k-', linewidth=2) # Ground
478
 
479
  # Player character
480
- ax.plot(2, 3.5, 'ro', markersize=15)
481
- ax.text(2, 4, 'Player', ha='center')
482
 
483
  # Goal
484
- ax.plot(8, 3.5, 'yo', markersize=15)
485
- ax.text(8, 4, 'Goal', ha='center')
486
 
487
  # Obstacles
488
  for i in range(3):
489
  x = random.uniform(3, 7)
490
- y = random.uniform(3.2, 4)
491
- ax.plot(x, y, 's', color='#8d99ae', markersize=12)
492
- ax.text(x, y+0.3, 'Obstacle', ha='center', fontsize=8)
493
 
494
  # Path
495
- ax.plot([2, 8], [3.5, 3.5], 'y--', linewidth=2)
496
 
497
  ax.axis('off')
498
- ax.set_title("Game Preview - Move player to collect goals while avoiding obstacles", fontsize=14)
499
 
500
  # Save to bytes
501
  buf = io.BytesIO()
502
- plt.savefig(buf, format='png', dpi=100, bbox_inches='tight')
503
  buf.seek(0)
504
  return buf
505
  except Exception as e:
506
  st.error(f"Preview generation error: {str(e)}")
507
  return None
508
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
  # Main application function
510
  def main():
511
  init_session_state()
512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
513
  st.title("🎮 StoryCoder - Learn Coding Through Games!")
514
- st.subheader("Turn your story into a 3D game and discover coding secrets!")
515
 
516
  # Create tabs
517
  st.markdown('<div class="tabs">', unsafe_allow_html=True)
@@ -579,7 +843,7 @@ def main():
579
  )
580
 
581
  with st.spinner("🖼️ Generating game preview..."):
582
- st.session_state.game_preview = generate_game_preview()
583
 
584
  st.session_state.active_tab = "game"
585
  st.session_state.loading = False
@@ -588,23 +852,29 @@ def main():
588
  # Show examples
589
  st.subheader("✨ Story Examples")
590
  col1, col2, col3 = st.columns(3)
 
 
 
 
 
 
591
  with col1:
592
  st.caption("Space Explorer")
593
  st.code('"An astronaut needs to collect 3 stars while avoiding asteroids"', language="text")
594
- st.image("https://i.imgur.com/7zQY1eE.gif",
595
- use_column_width=True,
596
  caption="Space Explorer Game")
597
  with col2:
598
  st.caption("Jungle Adventure")
599
  st.code('"A monkey swings through trees to collect bananas before sunset"', language="text")
600
- st.image("https://i.imgur.com/5X8jYAy.gif",
601
- use_column_width=True,
602
  caption="Jungle Adventure Game")
603
  with col3:
604
  st.caption("Dragon Quest")
605
  st.code('"A dragon flies through clouds to collect magic crystals"', language="text")
606
- st.image("https://i.imgur.com/9zJkQ7P.gif",
607
- use_column_width=True,
608
  caption="Dragon Quest Game")
609
 
610
  # Game tab
@@ -626,14 +896,17 @@ def main():
626
  st.image(st.session_state.game_preview, use_container_width=True)
627
  else:
628
  st.info("Game preview visualization")
629
- st.image("https://i.imgur.com/7zQY1eE.gif", use_container_width=True)
 
 
 
630
 
631
  # Game explanation
632
  st.subheader("📚 How This Game Teaches Coding")
633
  st.markdown(f'<div class="game-card">{st.session_state.game_explanation}</div>', unsafe_allow_html=True)
634
 
635
  # Play instructions
636
- st.subheader("▶️ How to Play")
637
  st.markdown("""
638
  <div class="game-card">
639
  <ol>
@@ -641,7 +914,7 @@ def main():
641
  <li>Install Python from <a href="https://python.org" target="_blank">python.org</a></li>
642
  <li>Install PyGame: <code>pip install pygame</code></li>
643
  <li>Run the game: <code>python your_game.py</code></li>
644
- <li>Use arrow keys to move your character!</li>
645
  </ol>
646
  </div>
647
  """, unsafe_allow_html=True)
@@ -705,7 +978,7 @@ def main():
705
  <li>Install PyGame: Open command prompt and type <code>pip install pygame</code></li>
706
  <li>Save the game code to a file named <code>my_game.py</code></li>
707
  <li>Run the game: <code>python my_game.py</code></li>
708
- <li>Use arrow keys to play!</li>
709
  </ol>
710
  </div>
711
  """, unsafe_allow_html=True)
@@ -715,9 +988,9 @@ def main():
715
  st.markdown("""
716
  <div class="game-card">
717
  <ul>
718
- <li>Move your character (red square) with arrow keys</li>
719
- <li>Collect the gold squares to increase your score</li>
720
- <li>Avoid the brown obstacles</li>
721
  <li>See how programming concepts make the game work!</li>
722
  </ul>
723
  </div>
 
1
+ # app.py - Enhanced Version with Groq API & Playable Games
2
  import streamlit as st
3
  import os
4
  import time
5
  import random
6
  import json
7
+ import re
8
  import base64
9
  import requests
 
10
  from PIL import Image
11
  import io
12
  import matplotlib.pyplot as plt
13
+ import numpy as np
14
+ from groq import Groq
15
+ from streamlit_js_eval import streamlit_js_eval
16
 
17
  # Configure Streamlit page
18
  st.set_page_config(
 
22
  initial_sidebar_state="expanded"
23
  )
24
 
25
+ # Custom CSS for game-themed UI with new color scheme
26
  st.markdown("""
27
  <style>
28
  @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Comic+Neue:wght@700&display=swap');
29
 
30
  :root {
31
+ --primary: #6A67CE;
32
+ --secondary: #FF7C7C;
33
+ --accent: #FDD85D;
34
+ --dark: #2D3250;
35
+ --light: #F0F0F0;
36
+ --game-blue: #1A8CD8;
37
  --game-purple: #9B5DE5;
38
  }
39
 
40
  body {
41
+ background: linear-gradient(135deg, #E6F7FF 0%, #FFEEF6 100%);
42
  font-family: 'Comic Neue', cursive;
43
  }
44
 
 
50
  background-color: white;
51
  border-radius: 20px;
52
  padding: 25px;
53
+ box-shadow: 0 8px 32px rgba(45, 50, 80, 0.15);
54
+ border: 4px solid var(--primary);
55
  margin-bottom: 25px;
56
  transition: all 0.3s;
57
  }
58
 
59
  .game-card:hover {
60
  transform: translateY(-5px);
61
+ box-shadow: 0 12px 24px rgba(45, 50, 80, 0.2);
62
  }
63
 
64
  .header {
 
68
  }
69
 
70
  .concept-card {
71
+ background: linear-gradient(145deg, #ffffff, #f5f5ff);
72
  border-radius: 15px;
73
  padding: 15px;
74
  margin: 10px 0;
75
+ border-left: 5px solid var(--accent);
76
+ box-shadow: 0 4px 12px rgba(0,0,0,0.08);
77
  }
78
 
79
  .stButton>button {
80
+ background: linear-gradient(45deg, var(--primary), var(--game-blue));
81
  color: white;
82
  border-radius: 50px;
83
  padding: 12px 28px;
84
  font-weight: bold;
85
+ font-size: 18px;
86
  border: none;
87
  transition: all 0.3s;
88
  font-family: 'Fredoka One', cursive;
 
90
 
91
  .stButton>button:hover {
92
  transform: scale(1.05);
93
+ box-shadow: 0 8px 16px rgba(106, 103, 206, 0.3);
94
  }
95
 
96
  .stTextInput>div>div>input {
 
112
 
113
  .tab {
114
  padding: 12px 24px;
115
+ background-color: var(--light);
116
  border-radius: 15px;
117
  cursor: pointer;
118
  font-weight: bold;
119
  white-space: nowrap;
120
  font-family: 'Fredoka One', cursive;
121
+ font-size: 16px;
122
  transition: all 0.3s;
123
+ color: var(--dark);
124
  }
125
 
126
  .tab.active {
127
+ background: linear-gradient(45deg, var(--primary), var(--game-blue));
128
  color: white;
129
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
130
  }
131
 
132
  .game-preview {
133
+ border: 4px solid var(--primary);
134
  border-radius: 20px;
135
  overflow: hidden;
136
+ background: linear-gradient(135deg, #d0e5ff, #e0d1ff);
137
  padding: 20px;
138
  margin: 20px 0;
139
  }
 
171
 
172
  .game-title {
173
  font-family: 'Fredoka One', cursive;
174
+ color: var(--primary);
175
  text-align: center;
176
  font-size: 32px;
177
  margin-bottom: 20px;
178
  text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
179
  }
180
 
181
+ .game-canvas {
182
+ width: 100%;
183
+ height: 400px;
184
+ background: #d0e5ff;
185
+ border-radius: 15px;
186
+ margin: 20px 0;
187
+ position: relative;
188
+ overflow: hidden;
189
+ }
190
+
191
+ .player {
192
+ position: absolute;
193
+ width: 40px;
194
+ height: 40px;
195
+ background: var(--primary);
196
+ border-radius: 50%;
197
+ transition: all 0.1s;
198
+ }
199
+
200
+ .goal {
201
+ position: absolute;
202
+ width: 30px;
203
+ height: 30px;
204
+ background: var(--accent);
205
+ border-radius: 50%;
206
+ box-shadow: 0 0 10px var(--accent);
207
+ }
208
+
209
+ .obstacle {
210
+ position: absolute;
211
+ background: var(--secondary);
212
+ border-radius: 5px;
213
+ }
214
+
215
+ .game-controls {
216
+ display: flex;
217
+ justify-content: center;
218
+ gap: 10px;
219
+ margin: 20px 0;
220
+ }
221
+
222
+ .control-btn {
223
+ width: 60px;
224
+ height: 60px;
225
+ border-radius: 50%;
226
+ background: var(--primary);
227
+ color: white;
228
+ display: flex;
229
+ align-items: center;
230
+ justify-content: center;
231
+ font-size: 24px;
232
+ cursor: pointer;
233
+ border: none;
234
+ box-shadow: 0 4px 8px rgba(0,0,0,0.2);
235
+ }
236
+
237
  @media (max-width: 768px) {
238
  .tabs {
239
  flex-wrap: wrap;
 
242
  .character {
243
  font-size: 48px;
244
  }
245
+
246
+ .control-btn {
247
+ width: 50px;
248
+ height: 50px;
249
+ font-size: 20px;
250
+ }
251
  }
252
  </style>
253
  """, unsafe_allow_html=True)
 
270
  st.session_state.active_tab = "story"
271
  if 'loading' not in st.session_state:
272
  st.session_state.loading = False
273
+ if 'game_state' not in st.session_state:
274
+ st.session_state.game_state = {
275
+ "player_x": 100,
276
+ "player_y": 200,
277
+ "score": 0,
278
+ "goal_x": 600,
279
+ "goal_y": 200,
280
+ "obstacles": [],
281
+ "game_active": False
282
+ }
283
+ if 'groq_api_key' not in st.session_state:
284
+ st.session_state.groq_api_key = ""
285
 
286
  # Concept database
287
  CONCEPTS = {
 
289
  "name": "Loop",
290
  "emoji": "🔄",
291
  "description": "Loops repeat actions multiple times",
292
+ "example": "for i in range(5):\n print('Jump!')",
293
+ "color": "#6A67CE",
294
+ "game_example": "Repeating jumps to cross a river"
295
  },
296
  "conditional": {
297
  "name": "Conditional",
298
  "emoji": "❓",
299
  "description": "Conditionals make decisions in code",
300
+ "example": "if key_found:\n open_door()\nelse:\n keep_searching()",
301
+ "color": "#FF7C7C",
302
+ "game_example": "Choosing paths based on obstacles"
303
  },
304
  "function": {
305
  "name": "Function",
306
  "emoji": "✨",
307
  "description": "Functions are reusable blocks of code",
308
+ "example": "def collect_star():\n score += 1\n play_sound()",
309
+ "color": "#FDD85D",
310
  "game_example": "Creating a jump function used multiple times"
311
  },
312
  "variable": {
313
  "name": "Variable",
314
  "emoji": "📦",
315
  "description": "Variables store information",
316
+ "example": "score = 0\nplayer_health = 100",
317
+ "color": "#1A8CD8",
318
+ "game_example": "Tracking collected stars"
319
  },
320
  "list": {
321
  "name": "List",
322
  "emoji": "📝",
323
  "description": "Lists store collections of items",
324
+ "example": "inventory = ['sword', 'shield', 'potion']",
325
+ "color": "#4CAF50",
326
+ "game_example": "Storing collected treasures"
327
  }
328
  }
329
 
330
+ # Initialize Groq client
331
+ def get_groq_client():
 
 
332
  try:
333
+ if st.session_state.groq_api_key:
334
+ return Groq(api_key=st.session_state.groq_api_key)
335
+ return None
336
  except:
337
  return None
338
 
 
342
  story_lower = story.lower()
343
  detected_concepts = []
344
 
345
+ # Improved concept detection
346
  # Check for loops
347
+ if any(word in story_lower for word in ["times", "repeat", "again", "multiple", "each", "every"]):
348
  detected_concepts.append("loop")
349
 
350
  # Check for conditionals
351
+ if any(word in story_lower for word in ["if", "when", "unless", "whether", "decide", "choice", "otherwise"]):
352
  detected_concepts.append("conditional")
353
 
354
  # Check for functions
355
+ if any(word in story_lower for word in ["make", "create", "do", "perform", "cast", "action", "use"]):
356
  detected_concepts.append("function")
357
 
358
  # Check for variables
359
+ if any(word in story_lower for word in ["is", "has", "set to", "value", "score", "count", "number"]):
360
  detected_concepts.append("variable")
361
 
362
  # Check for lists
363
+ if any(word in story_lower for word in ["and", "many", "several", "collection", "items", "group", "set of"]):
364
  detected_concepts.append("list")
365
 
366
+ return list(set(detected_concepts)) if detected_concepts else ["variable", "function"]
367
 
368
+ # Generate game scenario using Groq
369
  def generate_game_scenario(story, concepts):
370
  """Generate a game scenario based on the story and concepts"""
371
+ try:
372
+ client = get_groq_client()
373
+ if client:
374
+ concept_names = [CONCEPTS[c]['name'] for c in concepts]
375
+ concept_list = ", ".join(concept_names)
376
+
377
+ system_prompt = (
378
+ "You are an expert in creating educational games for children aged 6-12. "
379
+ "Create a simple 3D-style game scenario based on the child's story. "
380
+ "The game should teach programming concepts through gameplay. "
381
+ "Structure your response with these sections:\n"
382
+ "Game Title: ...\n"
383
+ "Game Objective: ...\n"
384
+ "Characters: ...\n"
385
+ "Game Mechanics: ...\n"
386
+ "Coding Concepts: Explain how these programming concepts are used: " + concept_list + "\n"
387
+ "Visual Description: Describe the game world visually\n"
388
+ "Keep it under 200 words and fun for kids."
389
+ )
390
+
391
+ response = client.chat.completions.create(
392
+ model="llama3-70b-8192",
393
+ messages=[
394
+ {"role": "system", "content": system_prompt},
395
+ {"role": "user", "content": story}
396
+ ],
397
+ temperature=0.8,
398
+ max_tokens=500
399
+ )
400
+ return response.choices[0].message.content
401
+ except Exception as e:
402
+ st.error(f"Game scenario generation error: {str(e)}")
403
+
404
+ # Fallback template
405
  concept_names = [CONCEPTS[c]['name'] for c in concepts]
406
  concept_list = ", ".join(concept_names)
 
407
  return f"""
408
  Game Title: {story[:15]} Adventure
409
+ Game Objective: Complete challenges based on your story: {story[:100]}...
410
  Characters:
411
  - Hero: The main character from your story
412
  - Helper: A friendly guide who explains coding concepts
413
  - Villain: A character that creates obstacles (if applicable)
414
 
415
  Game Mechanics:
416
+ 1. Move your character using arrow keys
417
+ 2. Collect items mentioned in your story
418
+ 3. Avoid obstacles and solve puzzles
419
  4. Helper characters appear to teach {concept_list}
420
 
421
  Coding Concepts: This game teaches {concept_list} through:
 
431
  # Generate game code explanation
432
  def generate_game_explanation(story, concepts, game_scenario):
433
  """Generate explanation of game code"""
434
+ try:
435
+ client = get_groq_client()
436
+ if client:
437
+ concept_names = [CONCEPTS[c]['name'] for c in concepts]
438
+ concept_list = ", ".join(concept_names)
439
+
440
+ system_prompt = (
441
+ "Explain how the game code implements programming concepts in a way "
442
+ "a child aged 6-12 can understand. Use simple analogies and relate to the story. "
443
+ "Structure your response with:\n"
444
+ "Introduction: ...\n"
445
+ "Concept 1: ... (with example from the game)\n"
446
+ "Concept 2: ... (with example from the game)\n"
447
+ "Conclusion: ...\n"
448
+ "Keep it under 300 words and engaging for kids."
449
+ )
450
+
451
+ response = client.chat.completions.create(
452
+ model="llama3-70b-8192",
453
+ messages=[
454
+ {"role": "system", "content": system_prompt},
455
+ {"role": "user", "content": f"Story: {story}\nGame Scenario: {game_scenario}\nConcepts: {concept_list}"}
456
+ ],
457
+ temperature=0.7,
458
+ max_tokens=600
459
+ )
460
+ return response.choices[0].message.content
461
+ except Exception as e:
462
+ st.error(f"Explanation generation error: {str(e)}")
463
+
464
+ # Fallback explanation
465
  concept_explanations = "\n".join(
466
  [f"- {CONCEPTS[c]['name']}: {CONCEPTS[c]['game_example']}" for c in concepts]
467
  )
 
480
  # Generate simple game code
481
  def generate_game_code(story, concepts):
482
  """Generate simple PyGame code for the game"""
483
+ # Extract keywords from story
484
  keywords = re.findall(r'\b\w{4,}\b', story)[:3]
485
+ player_char = keywords[0].capitalize() if keywords else "Hero"
486
  collect_item = keywords[1] if len(keywords) > 1 else "star"
487
  obstacle = keywords[2] if len(keywords) > 2 else "rock"
488
 
489
+ # Get concept emojis
490
+ concept_emojis = "".join([CONCEPTS[c]['emoji'] for c in concepts])
491
+
492
  return f"""
493
+ # {player_char}'s Adventure: {story[:20]}...
494
+ # Teaches: {concept_emojis} {", ".join([CONCEPTS[c]['name'] for c in concepts])}
495
+
496
  import pygame
497
  import random
498
  import sys
 
503
  # Game setup
504
  WIDTH, HEIGHT = 800, 600
505
  screen = pygame.display.set_mode((WIDTH, HEIGHT))
506
+ pygame.display.set_caption("{player_char}'s Adventure")
507
  clock = pygame.time.Clock()
508
 
509
  # Colors
510
+ BACKGROUND = (230, 240, 255) # Light blue
511
+ PLAYER_COLOR = (106, 103, 206) # Purple
512
+ GOAL_COLOR = (253, 216, 93) # Yellow
513
+ OBSTACLE_COLOR = (255, 124, 124) # Coral
514
+ TEXT_COLOR = (45, 50, 80) # Dark blue
515
 
516
  # Player setup
517
+ player_size = 40
518
  player_x = 100
519
  player_y = HEIGHT // 2
520
  player_speed = 5
521
 
522
  # Goal setup
523
+ goal_size = 30
524
  goal_x = WIDTH - 150
525
  goal_y = HEIGHT // 2
526
 
 
534
  obstacles.append([
535
  random.randint(200, WIDTH - 100),
536
  random.randint(50, HEIGHT - 100),
537
+ random.randint(30, 70),
538
  random.randint(20, 50)
539
  ])
540
 
 
548
 
549
  # Player movement
550
  keys = pygame.key.get_pressed()
551
+ if keys[pygame.K_UP] or keys[pygame.K_w]:
552
  player_y -= player_speed
553
+ if keys[pygame.K_DOWN] or keys[pygame.K_s]:
554
  player_y += player_speed
555
+ if keys[pygame.K_LEFT] or keys[pygame.K_a]:
556
  player_x -= player_speed
557
+ if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
558
  player_x += player_speed
559
 
560
  # Boundary checking
 
584
  # Draw player and goal
585
  pygame.draw.rect(screen, PLAYER_COLOR,
586
  (player_x, player_y, player_size, player_size))
587
+ pygame.draw.circle(screen, GOAL_COLOR,
588
+ (goal_x + goal_size//2, goal_y + goal_size//2), goal_size//2)
589
 
590
  # Display score
591
  score_text = font.render(f"{collect_item.capitalize()}s: {{score}}", True, TEXT_COLOR)
592
  screen.blit(score_text, (20, 20))
593
 
594
  # Display story title
595
+ title_text = font.render(f"{player_char}'s Adventure: {story[:20]}...", True, TEXT_COLOR)
596
+ screen.blit(title_text, (WIDTH // 2 - 150, 20))
597
+
598
+ # Display concepts
599
+ concepts_text = font.render(f"Teaches: {', '.join([CONCEPTS[c]['name'] for c in concepts])}", True, TEXT_COLOR)
600
+ screen.blit(concepts_text, (20, HEIGHT - 40))
601
 
602
  # Display instructions
603
+ help_text = font.render("Arrow keys to move - Collect the yellow circles!", True, TEXT_COLOR)
604
+ screen.blit(help_text, (WIDTH // 2 - 200, HEIGHT - 80))
605
 
606
  # Update display
607
  pygame.display.flip()
 
612
  """
613
 
614
  # Generate game preview visualization
615
+ def generate_game_preview(story):
616
  """Generate a visual preview of the game"""
617
  try:
618
+ # Extract keywords for theme
619
+ theme = "space" if "space" in story.lower() else "jungle" if "jungle" in story.lower() else "fantasy"
620
+
621
  # Create a simple visualization
622
  fig, ax = plt.subplots(figsize=(10, 6))
623
+
624
+ if theme == "space":
625
+ bg_color = '#0B0B2B'
626
+ player_color = '#6A67CE'
627
+ goal_color = '#FDD85D'
628
+ obstacle_color = '#FF7C7C'
629
+ title = "Space Adventure"
630
+ elif theme == "jungle":
631
+ bg_color = '#143D2C'
632
+ player_color = '#6A67CE'
633
+ goal_color = '#FDD85D'
634
+ obstacle_color = '#D35400'
635
+ title = "Jungle Adventure"
636
+ else:
637
+ bg_color = '#3A015C'
638
+ player_color = '#6A67CE'
639
+ goal_color = '#FDD85D'
640
+ obstacle_color = '#FF7C7C'
641
+ title = "Fantasy Quest"
642
+
643
+ ax.set_facecolor(bg_color)
644
  ax.set_xlim(0, 10)
645
  ax.set_ylim(0, 6)
646
 
647
  # Draw game elements
648
+ ax.text(5, 5, title, fontsize=20, ha='center', color='white')
649
+ ax.plot([1, 9], [1, 1], 'w-', linewidth=2) # Ground
650
 
651
  # Player character
652
+ ax.plot(2, 2, 'o', markersize=15, color=player_color)
653
+ ax.text(2, 2.7, 'You', ha='center', color='white', fontsize=12)
654
 
655
  # Goal
656
+ ax.plot(8, 2, 'o', markersize=12, color=goal_color)
657
+ ax.text(8, 2.7, 'Goal', ha='center', color='white', fontsize=12)
658
 
659
  # Obstacles
660
  for i in range(3):
661
  x = random.uniform(3, 7)
662
+ y = random.uniform(1.5, 2.5)
663
+ ax.plot(x, y, 's', markersize=15, color=obstacle_color)
664
+ ax.text(x, y+0.4, 'Obstacle', ha='center', color='white', fontsize=8)
665
 
666
  # Path
667
+ ax.plot([2, 8], [2, 2], 'y--', linewidth=1, alpha=0.5)
668
 
669
  ax.axis('off')
670
+ ax.set_title("Game Preview", fontsize=16, color='white')
671
 
672
  # Save to bytes
673
  buf = io.BytesIO()
674
+ plt.savefig(buf, format='png', dpi=100, bbox_inches='tight', facecolor=bg_color)
675
  buf.seek(0)
676
  return buf
677
  except Exception as e:
678
  st.error(f"Preview generation error: {str(e)}")
679
  return None
680
 
681
+ # Create a playable game in the browser
682
+ def create_playable_game():
683
+ """Create an interactive game using Streamlit components"""
684
+ st.subheader("🎮 Play Your Game in the Browser!")
685
+
686
+ # Initialize game state
687
+ if 'game_state' not in st.session_state:
688
+ st.session_state.game_state = {
689
+ "player_x": 100,
690
+ "player_y": 200,
691
+ "score": 0,
692
+ "goal_x": 600,
693
+ "goal_y": 200,
694
+ "obstacles": [
695
+ {"x": 300, "y": 150, "w": 80, "h": 30},
696
+ {"x": 400, "y": 250, "w": 60, "h": 40},
697
+ {"x": 200, "y": 300, "w": 100, "h": 25}
698
+ ],
699
+ "game_active": True
700
+ }
701
+
702
+ state = st.session_state.game_state
703
+
704
+ # Game canvas
705
+ st.markdown(f"""
706
+ <div class="game-canvas">
707
+ <div class="player" style="left:{state['player_x']}px; top:{state['player_y']}px;"></div>
708
+ <div class="goal" style="left:{state['goal_x']}px; top:{state['goal_y']}px;"></div>
709
+ {''.join([
710
+ f'<div class="obstacle" style="left:{obs["x"]}px; top:{obs["y"]}px; width:{obs["w"]}px; height:{obs["h"]}px;"></div>'
711
+ for obs in state['obstacles']
712
+ ])}
713
+ </div>
714
+ <div style="text-align:center; font-size:24px; font-family:'Fredoka One'; color: var(--dark);">
715
+ Stars Collected: {state['score']}
716
+ </div>
717
+ """, unsafe_allow_html=True)
718
+
719
+ # Game controls
720
+ st.markdown("""
721
+ <div class="game-controls">
722
+ <button class="control-btn" onclick="movePlayer('up')">↑</button>
723
+ <div>
724
+ <button class="control-btn" onclick="movePlayer('left')">←</button>
725
+ <button class="control-btn" style="margin:0 10px;" onclick="movePlayer('down')">↓</button>
726
+ <button class="control-btn" onclick="movePlayer('right')">→</button>
727
+ </div>
728
+ </div>
729
+
730
+ <script>
731
+ function movePlayer(direction) {
732
+ Streamlit.setComponentValue(direction);
733
+ }
734
+ </script>
735
+ """, unsafe_allow_html=True)
736
+
737
+ # Handle movement
738
+ direction = streamlit_js_eval(js_expressions="parent.document.querySelector('.game-controls').lastDirection", want_output=True)
739
+
740
+ if direction:
741
+ if direction == "up" and state['player_y'] > 20:
742
+ state['player_y'] -= 20
743
+ elif direction == "down" and state['player_y'] < 360:
744
+ state['player_y'] += 20
745
+ elif direction == "left" and state['player_x'] > 20:
746
+ state['player_x'] -= 20
747
+ elif direction == "right" and state['player_x'] < 740:
748
+ state['player_x'] += 20
749
+
750
+ # Check for collision with goal
751
+ if (abs(state['player_x'] - state['goal_x']) < 40 and
752
+ abs(state['player_y'] - state['goal_y']) < 40):
753
+ state['score'] += 1
754
+ state['goal_x'] = random.randint(100, 700)
755
+ state['goal_y'] = random.randint(50, 350)
756
+
757
+ st.session_state.game_state = state
758
+ st.rerun()
759
+
760
  # Main application function
761
  def main():
762
  init_session_state()
763
 
764
+ # Sidebar for API key
765
+ with st.sidebar:
766
+ st.header("⚙️ Settings")
767
+ st.session_state.groq_api_key = st.text_input(
768
+ "Enter Groq API Key (optional):",
769
+ type="password",
770
+ help="Get a free key from https://console.groq.com/keys"
771
+ )
772
+ st.caption("Using Groq API will create more creative and personalized games!")
773
+ st.divider()
774
+ st.caption("Made with ❤️ for kids learning to code")
775
+ st.caption("v2.0 | StoryCoder")
776
+
777
  st.title("🎮 StoryCoder - Learn Coding Through Games!")
778
+ st.subheader("Turn your story into a playable game and discover coding secrets!")
779
 
780
  # Create tabs
781
  st.markdown('<div class="tabs">', unsafe_allow_html=True)
 
843
  )
844
 
845
  with st.spinner("🖼️ Generating game preview..."):
846
+ st.session_state.game_preview = generate_game_preview(story)
847
 
848
  st.session_state.active_tab = "game"
849
  st.session_state.loading = False
 
852
  # Show examples
853
  st.subheader("✨ Story Examples")
854
  col1, col2, col3 = st.columns(3)
855
+ example_images = {
856
+ "Space Explorer": "https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=500",
857
+ "Jungle Adventure": "https://images.unsplash.com/photo-1546182990-dffeafbe841d?w=500",
858
+ "Dragon Quest": "https://images.unsplash.com/photo-1541414779316-9564c1f85944?w=500"
859
+ }
860
+
861
  with col1:
862
  st.caption("Space Explorer")
863
  st.code('"An astronaut needs to collect 3 stars while avoiding asteroids"', language="text")
864
+ st.image(example_images["Space Explorer"],
865
+ use_container_width=True,
866
  caption="Space Explorer Game")
867
  with col2:
868
  st.caption("Jungle Adventure")
869
  st.code('"A monkey swings through trees to collect bananas before sunset"', language="text")
870
+ st.image(example_images["Jungle Adventure"],
871
+ use_container_width=True,
872
  caption="Jungle Adventure Game")
873
  with col3:
874
  st.caption("Dragon Quest")
875
  st.code('"A dragon flies through clouds to collect magic crystals"', language="text")
876
+ st.image(example_images["Dragon Quest"],
877
+ use_container_width=True,
878
  caption="Dragon Quest Game")
879
 
880
  # Game tab
 
896
  st.image(st.session_state.game_preview, use_container_width=True)
897
  else:
898
  st.info("Game preview visualization")
899
+ st.image("https://images.unsplash.com/photo-1542751110-97427bbecf20?w=500", use_container_width=True)
900
+
901
+ # Playable game
902
+ create_playable_game()
903
 
904
  # Game explanation
905
  st.subheader("📚 How This Game Teaches Coding")
906
  st.markdown(f'<div class="game-card">{st.session_state.game_explanation}</div>', unsafe_allow_html=True)
907
 
908
  # Play instructions
909
+ st.subheader("▶️ How to Play the Full Game")
910
  st.markdown("""
911
  <div class="game-card">
912
  <ol>
 
914
  <li>Install Python from <a href="https://python.org" target="_blank">python.org</a></li>
915
  <li>Install PyGame: <code>pip install pygame</code></li>
916
  <li>Run the game: <code>python your_game.py</code></li>
917
+ <li>Use arrow keys or WASD to move your character!</li>
918
  </ol>
919
  </div>
920
  """, unsafe_allow_html=True)
 
978
  <li>Install PyGame: Open command prompt and type <code>pip install pygame</code></li>
979
  <li>Save the game code to a file named <code>my_game.py</code></li>
980
  <li>Run the game: <code>python my_game.py</code></li>
981
+ <li>Use arrow keys or WASD to play!</li>
982
  </ol>
983
  </div>
984
  """, unsafe_allow_html=True)
 
988
  st.markdown("""
989
  <div class="game-card">
990
  <ul>
991
+ <li>Move your character (purple square) with arrow keys</li>
992
+ <li>Collect the yellow circles to increase your score</li>
993
+ <li>Avoid the coral obstacles</li>
994
  <li>See how programming concepts make the game work!</li>
995
  </ul>
996
  </div>