sunbal7 commited on
Commit
8e6eb71
·
verified ·
1 Parent(s): abe98df

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +394 -325
app.py CHANGED
@@ -1,28 +1,25 @@
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(
19
- page_title="StoryCoder - Learn Coding Through Games",
20
  page_icon="🎮",
21
  layout="wide",
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');
@@ -38,42 +35,52 @@ st.markdown("""
38
  }
39
 
40
  body {
41
- background: linear-gradient(135deg, #E6F7FF 0%, #FFEEF6 100%);
 
 
42
  font-family: 'Comic Neue', cursive;
43
  }
44
 
 
 
 
 
 
 
45
  .stApp {
46
- background: url('https://www.transparenttextures.com/patterns/cartographer.png');
 
 
47
  }
48
 
49
  .game-card {
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 {
65
- color: var(--dark);
66
  font-family: 'Fredoka One', cursive;
67
- text-shadow: 2px 2px 4px rgba(0,0,0,0.1);
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 {
@@ -98,6 +105,7 @@ st.markdown("""
98
  padding: 14px;
99
  border: 3px solid var(--accent);
100
  font-size: 18px;
 
101
  }
102
 
103
  .tabs {
@@ -105,14 +113,15 @@ st.markdown("""
105
  gap: 10px;
106
  margin-bottom: 20px;
107
  overflow-x: auto;
108
- background: rgba(255,255,255,0.7);
109
  padding: 10px;
110
  border-radius: 20px;
 
111
  }
112
 
113
  .tab {
114
  padding: 12px 24px;
115
- background-color: var(--light);
116
  border-radius: 15px;
117
  cursor: pointer;
118
  font-weight: bold;
@@ -120,12 +129,11 @@ st.markdown("""
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
 
@@ -146,7 +154,7 @@ st.markdown("""
146
  }
147
 
148
  .game-container {
149
- background: rgba(255,255,255,0.9);
150
  border-radius: 20px;
151
  padding: 30px;
152
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
@@ -171,67 +179,97 @@ st.markdown("""
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) {
@@ -244,9 +282,14 @@ st.markdown("""
244
  }
245
 
246
  .control-btn {
247
- width: 50px;
248
- height: 50px;
249
- font-size: 20px;
 
 
 
 
 
250
  }
251
  }
252
  </style>
@@ -271,17 +314,25 @@ def init_session_state():
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 = {
@@ -376,7 +427,7 @@ def generate_game_scenario(story, concepts):
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"
@@ -414,8 +465,8 @@ Characters:
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:
@@ -425,7 +476,7 @@ Coding Concepts: This game teaches {concept_list} through:
425
  - Tracking progress with variables
426
  - Managing collections with lists
427
 
428
- Visual Description: Colorful 3D world with cartoon-style characters, vibrant landscapes, and magical effects.
429
  """
430
 
431
  # Generate game code explanation
@@ -474,141 +525,7 @@ As you play the game, think about:
474
  1. How the game uses these concepts to create challenges
475
  2. How you might change the code to make the game easier or harder
476
 
477
- The code brings your story to life in a 3D game world!
478
- """
479
-
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
499
-
500
- # Initialize pygame
501
- pygame.init()
502
-
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
-
527
- # Variables concept: Tracking score
528
- score = 0
529
- font = pygame.font.SysFont(None, 36)
530
-
531
- # List concept: Creating obstacles
532
- obstacles = []
533
- for i in range(5):
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
-
541
- # Game loop
542
- running = True
543
- while running:
544
- # Event handling
545
- for event in pygame.event.get():
546
- if event.type == pygame.QUIT:
547
- running = False
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
561
- player_x = max(0, min(WIDTH - player_size, player_x))
562
- player_y = max(0, min(HEIGHT - player_size, player_y))
563
-
564
- # Collision detection with goal
565
- player_rect = pygame.Rect(player_x, player_y, player_size, player_size)
566
- goal_rect = pygame.Rect(goal_x, goal_y, goal_size, goal_size)
567
-
568
- # Conditional concept: Check for collision
569
- if player_rect.colliderect(goal_rect):
570
- # Function concept: Increase score
571
- score += 1
572
- # Move goal to new position
573
- goal_x = random.randint(100, WIDTH - 100)
574
- goal_y = random.randint(50, HEIGHT - 100)
575
-
576
- # Drawing
577
- screen.fill(BACKGROUND)
578
-
579
- # Draw obstacles
580
- for obstacle in obstacles:
581
- pygame.draw.rect(screen, OBSTACLE_COLOR,
582
- (obstacle[0], obstacle[1], obstacle[2], obstacle[3]))
583
-
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()
608
- clock.tick(60)
609
-
610
- pygame.quit()
611
- sys.exit()
612
  """
613
 
614
  # Generate game preview visualization
@@ -678,84 +595,110 @@ def generate_game_preview(story):
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():
@@ -770,12 +713,36 @@ def main():
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)
@@ -801,13 +768,14 @@ def main():
801
  st.session_state.game_explanation = ""
802
  st.session_state.game_preview = None
803
  st.session_state.active_tab = "story"
 
804
  st.markdown('</div>', unsafe_allow_html=True)
805
 
806
  # Story creation tab
807
  if st.session_state.active_tab == "story":
808
  with st.container():
809
  st.header("📖 Create Your Story")
810
- st.write("Write a short story (2-5 sentences) and I'll turn it into a 3D game!")
811
 
812
  story = st.text_area(
813
  "Your story:",
@@ -827,16 +795,11 @@ def main():
827
  with st.spinner("🧠 Analyzing your story for coding concepts..."):
828
  st.session_state.concepts = analyze_story(story)
829
 
830
- with st.spinner("🎮 Creating your 3D game scenario..."):
831
  st.session_state.game_scenario = generate_game_scenario(
832
  story, st.session_state.concepts
833
  )
834
 
835
- with st.spinner("💻 Generating game code..."):
836
- st.session_state.game_code = generate_game_code(
837
- story, st.session_state.concepts
838
- )
839
-
840
  with st.spinner("📚 Creating coding explanations..."):
841
  st.session_state.game_explanation = generate_game_explanation(
842
  story, st.session_state.concepts, st.session_state.game_scenario
@@ -845,6 +808,7 @@ def main():
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
850
  st.rerun()
@@ -905,20 +869,6 @@ def main():
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>
913
- <li>Download the game code from the <b>Game Code</b> tab</li>
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)
921
-
922
  if st.button("Learn Coding Concepts", use_container_width=True):
923
  st.session_state.active_tab = "concepts"
924
  st.rerun()
@@ -955,49 +905,168 @@ def main():
955
  st.header("💻 Game Code")
956
  st.write("Here's the Python code for your game. Download it and run on your computer!")
957
 
958
- if st.session_state.game_code:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
959
  # Display code with syntax highlighting
960
  st.subheader("Your Game Code")
961
- st.code(st.session_state.game_code, language="python")
962
 
963
  # Download button
964
  st.download_button(
965
  label="📥 Download Game Code",
966
- data=st.session_state.game_code,
967
  file_name="story_game.py",
968
  mime="text/python",
969
  use_container_width=True
970
  )
971
-
972
- # Game running instructions
973
- st.subheader("🖥️ How to Run Your Game")
974
- st.markdown("""
975
- <div class="game-card">
976
- <ol>
977
- <li>Install Python from <a href="https://python.org" target="_blank">python.org</a></li>
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)
985
-
986
- # What to expect
987
- st.subheader("🎮 What to Expect When Playing")
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>
997
- """, unsafe_allow_html=True)
998
  else:
999
  st.warning("No game code generated yet!")
1000
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1001
  if st.button("Create Another Story!", use_container_width=True):
1002
  st.session_state.active_tab = "story"
1003
  st.rerun()
 
1
+ # app.py - Enhanced Version with Playable Online Game
2
  import streamlit as st
 
 
3
  import random
 
4
  import re
5
+ import time
6
  import base64
7
+ import json
8
  import requests
9
  from PIL import Image
10
  import io
11
  import matplotlib.pyplot as plt
 
12
  from groq import Groq
 
13
 
14
  # Configure Streamlit page
15
  st.set_page_config(
16
+ page_title="StoryCoder - Play & Learn Coding",
17
  page_icon="🎮",
18
  layout="wide",
19
  initial_sidebar_state="expanded"
20
  )
21
 
22
+ # Custom CSS with modern gradient background
23
  st.markdown("""
24
  <style>
25
  @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Comic+Neue:wght@700&display=swap');
 
35
  }
36
 
37
  body {
38
+ background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c);
39
+ background-size: 400% 400%;
40
+ animation: gradientBG 15s ease infinite;
41
  font-family: 'Comic Neue', cursive;
42
  }
43
 
44
+ @keyframes gradientBG {
45
+ 0% {background-position: 0% 50%;}
46
+ 50% {background-position: 100% 50%;}
47
+ 100% {background-position: 0% 50%;}
48
+ }
49
+
50
  .stApp {
51
+ background: rgba(255, 255, 255, 0.1);
52
+ backdrop-filter: blur(10px);
53
+ -webkit-backdrop-filter: blur(10px);
54
  }
55
 
56
  .game-card {
57
+ background: rgba(255, 255, 255, 0.85);
58
  border-radius: 20px;
59
  padding: 25px;
60
+ box-shadow: 0 8px 32px rgba(31, 38, 135, 0.37);
61
+ border: 2px solid rgba(255, 255, 255, 0.18);
62
  margin-bottom: 25px;
63
  transition: all 0.3s;
64
  }
65
 
66
  .game-card:hover {
67
  transform: translateY(-5px);
68
+ box-shadow: 0 12px 24px rgba(31, 38, 135, 0.5);
69
  }
70
 
71
  .header {
72
+ color: white;
73
  font-family: 'Fredoka One', cursive;
74
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
75
  }
76
 
77
  .concept-card {
78
+ background: rgba(255, 255, 255, 0.9);
79
  border-radius: 15px;
80
  padding: 15px;
81
  margin: 10px 0;
82
  border-left: 5px solid var(--accent);
83
+ box-shadow: 0 4px 12px rgba(0,0,0,0.1);
84
  }
85
 
86
  .stButton>button {
 
105
  padding: 14px;
106
  border: 3px solid var(--accent);
107
  font-size: 18px;
108
+ background: rgba(255, 255, 255, 0.9);
109
  }
110
 
111
  .tabs {
 
113
  gap: 10px;
114
  margin-bottom: 20px;
115
  overflow-x: auto;
116
+ background: rgba(255, 255, 255, 0.2);
117
  padding: 10px;
118
  border-radius: 20px;
119
+ backdrop-filter: blur(5px);
120
  }
121
 
122
  .tab {
123
  padding: 12px 24px;
124
+ background: rgba(255, 255, 255, 0.3);
125
  border-radius: 15px;
126
  cursor: pointer;
127
  font-weight: bold;
 
129
  font-family: 'Fredoka One', cursive;
130
  font-size: 16px;
131
  transition: all 0.3s;
132
+ color: white;
133
  }
134
 
135
  .tab.active {
136
  background: linear-gradient(45deg, var(--primary), var(--game-blue));
 
137
  box-shadow: 0 4px 8px rgba(0,0,0,0.1);
138
  }
139
 
 
154
  }
155
 
156
  .game-container {
157
+ background: rgba(255, 255, 255, 0.9);
158
  border-radius: 20px;
159
  padding: 30px;
160
  box-shadow: 0 8px 32px rgba(0,0,0,0.1);
 
179
 
180
  .game-title {
181
  font-family: 'Fredoka One', cursive;
182
+ color: white;
183
  text-align: center;
184
  font-size: 32px;
185
  margin-bottom: 20px;
186
+ text-shadow: 2px 2px 4px rgba(0,0,0,0.3);
187
  }
188
 
189
+ .game-board {
190
+ display: grid;
191
+ grid-template-columns: repeat(8, 1fr);
192
+ grid-template-rows: repeat(8, 1fr);
193
+ gap: 4px;
194
+ width: 500px;
195
+ height: 500px;
196
+ margin: 0 auto;
197
+ background: rgba(106, 103, 206, 0.2);
198
+ padding: 10px;
199
  border-radius: 15px;
200
+ }
201
+
202
+ .cell {
203
+ display: flex;
204
+ justify-content: center;
205
+ align-items: center;
206
+ border-radius: 8px;
207
+ font-size: 30px;
208
+ background: rgba(255, 255, 255, 0.8);
209
+ transition: all 0.2s;
210
+ cursor: pointer;
211
+ }
212
+
213
+ .cell:hover {
214
+ transform: scale(1.05);
215
+ background: rgba(255, 255, 255, 1);
216
  }
217
 
218
  .player {
219
+ background: linear-gradient(45deg, #6A67CE, #1A8CD8);
220
+ color: white;
 
 
 
 
221
  }
222
 
223
  .goal {
224
+ background: linear-gradient(45deg, #FDD85D, #FFB347);
 
 
 
 
 
225
  }
226
 
227
  .obstacle {
228
+ background: linear-gradient(45deg, #FF7C7C, #FF5252);
229
+ }
230
+
231
+ .empty {
232
+ background: rgba(255, 255, 255, 0.9);
233
  }
234
 
235
  .game-controls {
236
  display: flex;
237
  justify-content: center;
238
+ gap: 15px;
239
+ margin: 25px 0;
240
  }
241
 
242
  .control-btn {
243
+ width: 70px;
244
+ height: 70px;
245
  border-radius: 50%;
246
+ background: linear-gradient(45deg, var(--primary), var(--game-blue));
247
  color: white;
248
  display: flex;
249
  align-items: center;
250
  justify-content: center;
251
+ font-size: 30px;
252
  cursor: pointer;
253
  border: none;
254
+ box-shadow: 0 6px 12px rgba(0,0,0,0.2);
255
+ transition: all 0.2s;
256
+ }
257
+
258
+ .control-btn:hover {
259
+ transform: scale(1.1);
260
+ box-shadow: 0 8px 16px rgba(0,0,0,0.3);
261
+ }
262
+
263
+ .score-board {
264
+ background: rgba(255, 255, 255, 0.85);
265
+ border-radius: 15px;
266
+ padding: 15px;
267
+ text-align: center;
268
+ font-family: 'Fredoka One', cursive;
269
+ font-size: 24px;
270
+ margin: 20px auto;
271
+ width: 300px;
272
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
273
  }
274
 
275
  @media (max-width: 768px) {
 
282
  }
283
 
284
  .control-btn {
285
+ width: 60px;
286
+ height: 60px;
287
+ font-size: 24px;
288
+ }
289
+
290
+ .game-board {
291
+ width: 90vw;
292
+ height: 90vw;
293
  }
294
  }
295
  </style>
 
314
  if 'loading' not in st.session_state:
315
  st.session_state.loading = False
316
  if 'game_state' not in st.session_state:
317
+ reset_game_state()
 
 
 
 
 
 
 
 
318
  if 'groq_api_key' not in st.session_state:
319
  st.session_state.groq_api_key = ""
320
+ if 'player_char' not in st.session_state:
321
+ st.session_state.player_char = "🦸"
322
+ if 'goal_char' not in st.session_state:
323
+ st.session_state.goal_char = "⭐"
324
+ if 'obstacle_char' not in st.session_state:
325
+ st.session_state.obstacle_char = "🪨"
326
+
327
+ def reset_game_state():
328
+ st.session_state.game_state = {
329
+ "player_pos": [0, 0],
330
+ "goal_pos": [7, 7],
331
+ "obstacles": [[2, 2], [3, 4], [5, 3], [4, 6], [6, 5]],
332
+ "score": 0,
333
+ "moves": 0,
334
+ "game_over": False
335
+ }
336
 
337
  # Concept database
338
  CONCEPTS = {
 
427
 
428
  system_prompt = (
429
  "You are an expert in creating educational games for children aged 6-12. "
430
+ "Create a simple game scenario based on the child's story. "
431
  "The game should teach programming concepts through gameplay. "
432
  "Structure your response with these sections:\n"
433
  "Game Title: ...\n"
 
465
 
466
  Game Mechanics:
467
  1. Move your character using arrow keys
468
+ 2. Collect stars while avoiding obstacles
469
+ 3. Reach the goal to win
470
  4. Helper characters appear to teach {concept_list}
471
 
472
  Coding Concepts: This game teaches {concept_list} through:
 
476
  - Tracking progress with variables
477
  - Managing collections with lists
478
 
479
+ Visual Description: Colorful game world with cartoon-style characters, vibrant landscapes, and magical effects.
480
  """
481
 
482
  # Generate game code explanation
 
525
  1. How the game uses these concepts to create challenges
526
  2. How you might change the code to make the game easier or harder
527
 
528
+ The code brings your story to life in a fun game world!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  """
530
 
531
  # Generate game preview visualization
 
595
  st.error(f"Preview generation error: {str(e)}")
596
  return None
597
 
598
+ # Handle player movement
599
+ def move_player(direction):
600
+ """Update player position based on movement direction"""
601
+ state = st.session_state.game_state
602
+ player_pos = state["player_pos"]
603
+ goal_pos = state["goal_pos"]
604
+ obstacles = state["obstacles"]
605
+
606
+ new_pos = player_pos.copy()
607
+
608
+ if direction == "up" and player_pos[0] > 0:
609
+ new_pos[0] -= 1
610
+ elif direction == "down" and player_pos[0] < 7:
611
+ new_pos[0] += 1
612
+ elif direction == "left" and player_pos[1] > 0:
613
+ new_pos[1] -= 1
614
+ elif direction == "right" and player_pos[1] < 7:
615
+ new_pos[1] += 1
616
+
617
+ # Check if new position is valid
618
+ if new_pos != player_pos:
619
+ # Check for obstacle collision
620
+ if new_pos not in obstacles:
621
+ state["player_pos"] = new_pos
622
+ state["moves"] += 1
623
+
624
+ # Check for goal collision
625
+ if new_pos == goal_pos:
626
+ state["score"] += 10
627
+ state["game_over"] = True
628
+ # Check for star collection
629
+ elif new_pos in [[3, 3], [4, 4], [5, 5]]:
630
+ state["score"] += 5
631
+
632
+ st.session_state.game_state = state
633
+
634
  # Create a playable game in the browser
635
  def create_playable_game():
636
+ """Create an interactive grid-based game"""
637
+ st.subheader("🎮 Play Your Game Now!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
638
 
639
  state = st.session_state.game_state
640
+ player_pos = state["player_pos"]
641
+ goal_pos = state["goal_pos"]
642
+ obstacles = state["obstacles"]
643
 
644
+ # Score board
645
  st.markdown(f"""
646
+ <div class="score-board">
647
+ Stars Collected: {state["score"]} &nbsp; | &nbsp; Moves: {state["moves"]}
 
 
 
 
 
 
 
 
648
  </div>
649
  """, unsafe_allow_html=True)
650
 
651
+ # Game board
652
+ st.markdown("<div class='game-board'>", unsafe_allow_html=True)
653
+
654
+ # Create grid cells
655
+ for row in range(8):
656
+ cols = st.columns(8)
657
+ for col in range(8):
658
+ pos = [row, col]
659
+ cell_class = "cell"
660
+
661
+ if pos == player_pos:
662
+ cell_class += " player"
663
+ cell_content = st.session_state.player_char
664
+ elif pos == goal_pos:
665
+ cell_class += " goal"
666
+ cell_content = "🏁"
667
+ elif pos in obstacles:
668
+ cell_class += " obstacle"
669
+ cell_content = st.session_state.obstacle_char
670
+ elif pos in [[3, 3], [4, 4], [5, 5]]:
671
+ cell_class += " goal"
672
+ cell_content = "⭐"
673
+ else:
674
+ cell_class += " empty"
675
+ cell_content = ""
676
+
677
+ with cols[col]:
678
+ st.markdown(f"<div class='{cell_class}'>{cell_content}</div>", unsafe_allow_html=True)
679
+
680
+ st.markdown("</div>", unsafe_allow_html=True)
681
+
682
  # Game controls
683
+ st.markdown("<div class='game-controls'>", unsafe_allow_html=True)
684
+ col1, col2, col3, col4 = st.columns(4)
685
+ with col1:
686
+ st.button("↑", key="up", on_click=move_player, args=("up",), use_container_width=True)
687
+ with col2:
688
+ st.button("←", key="left", on_click=move_player, args=("left",), use_container_width=True)
689
+ with col3:
690
+ st.button("↓", key="down", on_click=move_player, args=("down",), use_container_width=True)
691
+ with col4:
692
+ st.button("→", key="right", on_click=move_player, args=("right",), use_container_width=True)
693
+ st.markdown("</div>", unsafe_allow_html=True)
694
 
695
+ # Reset button
696
+ st.button("🔄 Reset Game", on_click=reset_game_state, use_container_width=True)
 
 
 
 
697
 
698
+ # Game over message
699
+ if state["game_over"]:
700
+ st.balloons()
701
+ st.success(f"🎉 You won! Final Score: {state['score']} in {state['moves']} moves!")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
702
 
703
  # Main application function
704
  def main():
 
713
  help="Get a free key from https://console.groq.com/keys"
714
  )
715
  st.caption("Using Groq API will create more creative and personalized games!")
716
+
717
+ st.divider()
718
+
719
+ st.header("🎮 Game Theme")
720
+ col1, col2, col3 = st.columns(3)
721
+ with col1:
722
+ st.session_state.player_char = st.selectbox(
723
+ "Player Character",
724
+ ["🦸", "👨‍🚀", "🧙‍♂️", "🐱", "🐉", "🦊"],
725
+ index=0
726
+ )
727
+ with col2:
728
+ st.session_state.goal_char = st.selectbox(
729
+ "Goal Character",
730
+ ["🏁", "🏰", "🚩", "🎯", "🔑"],
731
+ index=0
732
+ )
733
+ with col3:
734
+ st.session_state.obstacle_char = st.selectbox(
735
+ "Obstacle Character",
736
+ ["🪨", "🌵", "🔥", "🌊", "🌳"],
737
+ index=0
738
+ )
739
+
740
  st.divider()
741
  st.caption("Made with ❤️ for kids learning to code")
742
+ st.caption("v3.0 | StoryCoder")
743
 
744
+ st.title("🎮 StoryCoder - Play & Learn Coding!")
745
+ st.subheader("Create your story, play the game, and learn programming concepts!")
746
 
747
  # Create tabs
748
  st.markdown('<div class="tabs">', unsafe_allow_html=True)
 
768
  st.session_state.game_explanation = ""
769
  st.session_state.game_preview = None
770
  st.session_state.active_tab = "story"
771
+ reset_game_state()
772
  st.markdown('</div>', unsafe_allow_html=True)
773
 
774
  # Story creation tab
775
  if st.session_state.active_tab == "story":
776
  with st.container():
777
  st.header("📖 Create Your Story")
778
+ st.write("Write a short story (2-5 sentences) and I'll turn it into a playable game!")
779
 
780
  story = st.text_area(
781
  "Your story:",
 
795
  with st.spinner("🧠 Analyzing your story for coding concepts..."):
796
  st.session_state.concepts = analyze_story(story)
797
 
798
+ with st.spinner("🎮 Creating your game scenario..."):
799
  st.session_state.game_scenario = generate_game_scenario(
800
  story, st.session_state.concepts
801
  )
802
 
 
 
 
 
 
803
  with st.spinner("📚 Creating coding explanations..."):
804
  st.session_state.game_explanation = generate_game_explanation(
805
  story, st.session_state.concepts, st.session_state.game_scenario
 
808
  with st.spinner("🖼️ Generating game preview..."):
809
  st.session_state.game_preview = generate_game_preview(story)
810
 
811
+ reset_game_state()
812
  st.session_state.active_tab = "game"
813
  st.session_state.loading = False
814
  st.rerun()
 
869
  st.subheader("📚 How This Game Teaches Coding")
870
  st.markdown(f'<div class="game-card">{st.session_state.game_explanation}</div>', unsafe_allow_html=True)
871
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
872
  if st.button("Learn Coding Concepts", use_container_width=True):
873
  st.session_state.active_tab = "concepts"
874
  st.rerun()
 
905
  st.header("💻 Game Code")
906
  st.write("Here's the Python code for your game. Download it and run on your computer!")
907
 
908
+ # Generate simple game code
909
+ if st.session_state.story and st.session_state.concepts:
910
+ # Extract keywords from story
911
+ keywords = re.findall(r'\b\w{4,}\b', st.session_state.story)[:3]
912
+ player_char = keywords[0].capitalize() if keywords else "Hero"
913
+ collect_item = keywords[1] if len(keywords) > 1 else "star"
914
+ obstacle = keywords[2] if len(keywords) > 2 else "rock"
915
+
916
+ # Get concept emojis
917
+ concept_emojis = "".join([CONCEPTS[c]['emoji'] for c in st.session_state.concepts])
918
+
919
+ game_code = f"""
920
+ # {player_char}'s Adventure: {st.session_state.story[:20]}...
921
+ # Teaches: {concept_emojis} {", ".join([CONCEPTS[c]['name'] for c in st.session_state.concepts])}
922
+
923
+ import pygame
924
+ import random
925
+ import sys
926
+
927
+ # Initialize pygame
928
+ pygame.init()
929
+
930
+ # Game setup
931
+ WIDTH, HEIGHT = 800, 600
932
+ screen = pygame.display.set_mode((WIDTH, HEIGHT))
933
+ pygame.display.set_caption("{player_char}'s Adventure")
934
+ clock = pygame.time.Clock()
935
+
936
+ # Colors
937
+ BACKGROUND = (230, 240, 255) # Light blue
938
+ PLAYER_COLOR = (106, 103, 206) # Purple
939
+ GOAL_COLOR = (253, 216, 93) # Yellow
940
+ OBSTACLE_COLOR = (255, 124, 124) # Coral
941
+ TEXT_COLOR = (45, 50, 80) # Dark blue
942
+
943
+ # Player setup
944
+ player_size = 40
945
+ player_x = 100
946
+ player_y = HEIGHT // 2
947
+ player_speed = 5
948
+
949
+ # Goal setup
950
+ goal_size = 30
951
+ goal_x = WIDTH - 150
952
+ goal_y = HEIGHT // 2
953
+
954
+ # Variables concept: Tracking score
955
+ score = 0
956
+ font = pygame.font.SysFont(None, 36)
957
+
958
+ # List concept: Creating obstacles
959
+ obstacles = []
960
+ for i in range(5):
961
+ obstacles.append([
962
+ random.randint(200, WIDTH - 100),
963
+ random.randint(50, HEIGHT - 100),
964
+ random.randint(30, 70),
965
+ random.randint(20, 50)
966
+ ])
967
+
968
+ # Game loop
969
+ running = True
970
+ while running:
971
+ # Event handling
972
+ for event in pygame.event.get():
973
+ if event.type == pygame.QUIT:
974
+ running = False
975
+
976
+ # Player movement
977
+ keys = pygame.key.get_pressed()
978
+ if keys[pygame.K_UP] or keys[pygame.K_w]:
979
+ player_y -= player_speed
980
+ if keys[pygame.K_DOWN] or keys[pygame.K_s]:
981
+ player_y += player_speed
982
+ if keys[pygame.K_LEFT] or keys[pygame.K_a]:
983
+ player_x -= player_speed
984
+ if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
985
+ player_x += player_speed
986
+
987
+ # Boundary checking
988
+ player_x = max(0, min(WIDTH - player_size, player_x))
989
+ player_y = max(0, min(HEIGHT - player_size, player_y))
990
+
991
+ # Collision detection with goal
992
+ player_rect = pygame.Rect(player_x, player_y, player_size, player_size)
993
+ goal_rect = pygame.Rect(goal_x, goal_y, goal_size, goal_size)
994
+
995
+ # Conditional concept: Check for collision
996
+ if player_rect.colliderect(goal_rect):
997
+ # Function concept: Increase score
998
+ score += 1
999
+ # Move goal to new position
1000
+ goal_x = random.randint(100, WIDTH - 100)
1001
+ goal_y = random.randint(50, HEIGHT - 100)
1002
+
1003
+ # Drawing
1004
+ screen.fill(BACKGROUND)
1005
+
1006
+ # Draw obstacles
1007
+ for obstacle in obstacles:
1008
+ pygame.draw.rect(screen, OBSTACLE_COLOR,
1009
+ (obstacle[0], obstacle[1], obstacle[2], obstacle[3]))
1010
+
1011
+ # Draw player and goal
1012
+ pygame.draw.rect(screen, PLAYER_COLOR,
1013
+ (player_x, player_y, player_size, player_size))
1014
+ pygame.draw.circle(screen, GOAL_COLOR,
1015
+ (goal_x + goal_size//2, goal_y + goal_size//2), goal_size//2)
1016
+
1017
+ # Display score
1018
+ score_text = font.render(f"{collect_item.capitalize()}s: {{score}}", True, TEXT_COLOR)
1019
+ screen.blit(score_text, (20, 20))
1020
+
1021
+ # Display story title
1022
+ title_text = font.render(f"{player_char}'s Adventure: {st.session_state.story[:20]}...", True, TEXT_COLOR)
1023
+ screen.blit(title_text, (WIDTH // 2 - 150, 20))
1024
+
1025
+ # Display concepts
1026
+ concepts_text = font.render(f"Teaches: {', '.join([CONCEPTS[c]['name'] for c in st.session_state.concepts])}", True, TEXT_COLOR)
1027
+ screen.blit(concepts_text, (20, HEIGHT - 40))
1028
+
1029
+ # Display instructions
1030
+ help_text = font.render("Arrow keys to move - Collect the yellow circles!", True, TEXT_COLOR)
1031
+ screen.blit(help_text, (WIDTH // 2 - 200, HEIGHT - 80))
1032
+
1033
+ # Update display
1034
+ pygame.display.flip()
1035
+ clock.tick(60)
1036
+
1037
+ pygame.quit()
1038
+ sys.exit()
1039
+ """
1040
+
1041
  # Display code with syntax highlighting
1042
  st.subheader("Your Game Code")
1043
+ st.code(game_code, language="python")
1044
 
1045
  # Download button
1046
  st.download_button(
1047
  label="📥 Download Game Code",
1048
+ data=game_code,
1049
  file_name="story_game.py",
1050
  mime="text/python",
1051
  use_container_width=True
1052
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1053
  else:
1054
  st.warning("No game code generated yet!")
1055
 
1056
+ # Game running instructions
1057
+ st.subheader("🖥️ How to Run Your Game")
1058
+ st.markdown("""
1059
+ <div class="game-card">
1060
+ <ol>
1061
+ <li>Install Python from <a href="https://python.org" target="_blank">python.org</a></li>
1062
+ <li>Install PyGame: Open command prompt and type <code>pip install pygame</code></li>
1063
+ <li>Save the game code to a file named <code>my_game.py</code></li>
1064
+ <li>Run the game: <code>python my_game.py</code></li>
1065
+ <li>Use arrow keys or WASD to play!</li>
1066
+ </ol>
1067
+ </div>
1068
+ """, unsafe_allow_html=True)
1069
+
1070
  if st.button("Create Another Story!", use_container_width=True):
1071
  st.session_state.active_tab = "story"
1072
  st.rerun()