sunbal7 commited on
Commit
7d0616b
·
verified ·
1 Parent(s): 154ab4d

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +278 -463
app.py CHANGED
@@ -19,7 +19,7 @@ st.set_page_config(
19
  initial_sidebar_state="expanded"
20
  )
21
 
22
- # Custom CSS with light purple background and wave design
23
  st.markdown("""
24
  <style>
25
  @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Comic+Neue:wght@700&display=swap');
@@ -29,140 +29,107 @@ st.markdown("""
29
  --secondary: #9370DB;
30
  --accent: #FFD700;
31
  --dark: #4B0082;
32
- --light: #E6E6FA;
33
  --game-blue: #6A5ACD;
34
  --game-purple: #9400D3;
35
- --gradient-start: #E6E6FA;
36
- --gradient-mid: #D8BFD8;
37
- --gradient-end: #DDA0DD;
38
  }
39
 
40
  body {
41
- background: linear-gradient(135deg, var(--gradient-start), var(--gradient-mid), var(--gradient-end));
42
- background-size: 400% 400%;
43
- animation: gradientBG 15s ease infinite;
44
  font-family: 'Comic Neue', cursive;
45
  margin: 0;
46
  padding: 0;
47
  min-height: 100vh;
48
  }
49
 
50
- @keyframes gradientBG {
51
- 0% {background-position: 0% 50%;}
52
- 50% {background-position: 100% 50%;}
53
- 100% {background-position: 0% 50%;}
54
- }
55
-
56
  .stApp {
57
- background: url('https://www.transparenttextures.com/patterns/always-grey.png');
58
- background-color: rgba(230, 230, 250, 0.9);
59
- backdrop-filter: blur(5px);
60
- -webkit-backdrop-filter: blur(5px);
61
- }
62
-
63
- .wave-divider {
64
- width: 100%;
65
- height: 150px;
66
- overflow: hidden;
67
- margin: -10px 0 20px 0;
68
- transform: rotate(180deg);
69
- }
70
-
71
- .wave-divider svg {
72
- height: 100%;
73
- width: 100%;
74
- }
75
-
76
- .wave-divider path {
77
- stroke: none;
78
- fill: var(--primary);
79
- opacity: 0.2;
80
  }
81
 
82
  .game-card {
83
- background: rgba(255, 255, 255, 0.85);
84
- border-radius: 20px;
85
- padding: 25px;
86
- box-shadow: 0 8px 32px rgba(138, 43, 226, 0.2);
87
- border: 2px solid rgba(255, 255, 255, 0.5);
88
- margin-bottom: 25px;
89
  transition: all 0.3s;
90
  }
91
 
92
  .game-card:hover {
93
- transform: translateY(-5px);
94
- box-shadow: 0 12px 24px rgba(138, 43, 226, 0.3);
95
  }
96
 
97
  .header {
98
  color: var(--dark);
99
  font-family: 'Fredoka One', cursive;
100
- text-shadow: 2px 2px 4px rgba(255, 255, 255, 0.8);
101
  }
102
 
103
  .concept-card {
104
- background: rgba(255, 255, 255, 0.9);
105
- border-radius: 15px;
106
  padding: 15px;
107
  margin: 10px 0;
108
- border-left: 5px solid var(--accent);
109
- box-shadow: 0 4px 12px rgba(0,0,0,0.1);
110
  }
111
 
112
  .stButton>button {
113
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
114
  color: white;
115
- border-radius: 50px;
116
- padding: 12px 28px;
117
  font-weight: bold;
118
- font-size: 18px;
119
  border: none;
120
  transition: all 0.3s;
121
  font-family: 'Fredoka One', cursive;
122
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
123
  }
124
 
125
  .stButton>button:hover {
126
- transform: scale(1.05);
127
- box-shadow: 0 8px 16px rgba(138, 43, 226, 0.4);
128
  }
129
 
130
  .stTextInput>div>div>input {
131
- border-radius: 20px;
132
- padding: 14px;
133
- border: 3px solid var(--accent);
134
- font-size: 18px;
135
- background: rgba(255, 255, 255, 0.9);
136
  }
137
 
138
  .tabs {
139
  display: flex;
140
- gap: 10px;
141
  margin-bottom: 20px;
142
  overflow-x: auto;
143
- background: rgba(255, 255, 255, 0.3);
144
- padding: 10px;
145
- border-radius: 20px;
146
- backdrop-filter: blur(5px);
147
  }
148
 
149
  .tab {
150
- padding: 12px 24px;
151
- background: rgba(255, 255, 255, 0.4);
152
- border-radius: 15px;
153
  cursor: pointer;
154
  font-weight: bold;
155
  white-space: nowrap;
156
  font-family: 'Fredoka One', cursive;
157
- font-size: 16px;
158
  transition: all 0.3s;
159
  color: var(--dark);
 
160
  }
161
 
162
  .tab.active {
163
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
164
  color: white;
165
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
166
  }
167
 
168
  .game-board {
@@ -170,132 +137,134 @@ st.markdown("""
170
  grid-template-columns: repeat(8, 1fr);
171
  grid-template-rows: repeat(8, 1fr);
172
  gap: 4px;
173
- width: 500px;
174
- height: 500px;
175
  margin: 0 auto;
176
- background: rgba(147, 112, 219, 0.2);
177
  padding: 10px;
178
- border-radius: 15px;
 
179
  }
180
 
181
  .cell {
182
  display: flex;
183
  justify-content: center;
184
  align-items: center;
185
- border-radius: 8px;
186
- font-size: 30px;
187
- background: rgba(255, 255, 255, 0.85);
188
  transition: all 0.2s;
189
  cursor: pointer;
190
- box-shadow: 0 2px 4px rgba(0,0,0,0.1);
 
191
  }
192
 
193
  .cell:hover {
194
- transform: scale(1.05);
195
- background: rgba(255, 255, 255, 1);
196
  }
197
 
198
  .player {
199
  background: linear-gradient(45deg, var(--primary), var(--game-blue));
200
  color: white;
201
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
202
  }
203
 
204
  .goal {
205
  background: linear-gradient(45deg, var(--accent), #FFA500);
206
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
207
  }
208
 
209
  .obstacle {
210
  background: linear-gradient(45deg, var(--secondary), #8A2BE2);
211
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
212
  }
213
 
214
  .star {
215
  background: linear-gradient(45deg, #FFD700, #FFA500);
216
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
217
  }
218
 
219
  .portal {
220
  background: linear-gradient(45deg, #9B5DE5, #6A0DAD);
221
- box-shadow: 0 4px 8px rgba(0,0,0,0.2);
222
  }
223
 
224
  .game-controls {
225
  display: flex;
226
  justify-content: center;
227
- gap: 15px;
228
- margin: 25px 0;
229
  }
230
 
231
  .control-btn {
232
- width: 70px;
233
- height: 70px;
234
  border-radius: 50%;
235
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
236
  color: white;
237
  display: flex;
238
  align-items: center;
239
  justify-content: center;
240
- font-size: 30px;
241
  cursor: pointer;
242
  border: none;
243
- box-shadow: 0 6px 12px rgba(0,0,0,0.2);
244
  transition: all 0.2s;
245
  }
246
 
247
  .control-btn:hover {
248
- transform: scale(1.1);
249
- box-shadow: 0 8px 16px rgba(0,0,0,0.3);
250
  }
251
 
252
  .score-board {
253
- background: rgba(255, 255, 255, 0.9);
254
- border-radius: 15px;
255
- padding: 15px;
256
  text-align: center;
257
  font-family: 'Fredoka One', cursive;
258
- font-size: 24px;
259
- margin: 20px auto;
260
- width: 300px;
261
- box-shadow: 0 4px 8px rgba(0,0,0,0.15);
262
- border: 2px solid var(--primary);
263
  }
264
 
265
  .level-indicator {
266
- background: rgba(255, 255, 255, 0.9);
267
- border-radius: 15px;
268
- padding: 10px 20px;
269
  text-align: center;
270
  font-family: 'Fredoka One', cursive;
271
- font-size: 20px;
272
- margin: 10px auto;
273
- width: 200px;
274
- box-shadow: 0 4px 8px rgba(0,0,0,0.1);
275
- border: 2px solid var(--accent);
276
  }
277
 
278
  .theme-customizer {
279
- background: rgba(255, 255, 255, 0.9);
280
- border-radius: 20px;
281
- padding: 20px;
282
- margin: 20px 0;
283
- box-shadow: 0 8px 16px rgba(138, 43, 226, 0.2);
284
- border: 3px solid var(--primary);
285
  }
286
 
287
  .customizer-title {
288
  text-align: center;
289
  font-family: 'Fredoka One', cursive;
290
  color: var(--primary);
291
- margin-bottom: 20px;
292
- font-size: 24px;
293
  }
294
 
295
  .char-preview {
296
  text-align: center;
297
- font-size: 48px;
298
- margin: 10px 0;
299
  }
300
 
301
  @media (max-width: 768px) {
@@ -304,46 +273,83 @@ st.markdown("""
304
  }
305
 
306
  .game-board {
307
- width: 90vw;
308
- height: 90vw;
309
  }
310
 
311
  .control-btn {
312
- width: 60px;
313
- height: 60px;
314
- font-size: 24px;
315
  }
316
  }
317
 
318
- .typewriter h2 {
319
- overflow: hidden;
320
- border-right: .15em solid var(--accent);
321
- white-space: nowrap;
322
- margin: 0 auto;
323
- letter-spacing: .15em;
324
- animation: typing 3.5s steps(40, end), blink-caret .75s step-end infinite;
325
- color: var(--dark);
326
- font-family: 'Fredoka One', cursive;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
327
  }
328
 
329
- @keyframes typing {
330
- from { width: 0 }
331
- to { width: 100% }
 
332
  }
333
 
334
- @keyframes blink-caret {
335
- from, to { border-color: transparent }
336
- 50% { border-color: var(--accent); }
 
 
 
 
337
  }
338
 
339
- .floating {
340
- animation: floating 3s ease-in-out infinite;
 
 
341
  }
342
 
343
- @keyframes floating {
344
- 0% { transform: translate(0, 0px); }
345
- 50% { transform: translate(0, 15px); }
346
- 100% { transform: translate(0, -0px); }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
347
  }
348
  </style>
349
  """, unsafe_allow_html=True)
@@ -360,8 +366,6 @@ def init_session_state():
360
  st.session_state.game_code = ""
361
  if 'game_explanation' not in st.session_state:
362
  st.session_state.game_explanation = ""
363
- if 'game_preview' not in st.session_state:
364
- st.session_state.game_preview = None
365
  if 'active_tab' not in st.session_state:
366
  st.session_state.active_tab = "story"
367
  if 'loading' not in st.session_state:
@@ -378,6 +382,10 @@ def init_session_state():
378
  st.session_state.current_level = 1
379
  if 'total_levels' not in st.session_state:
380
  st.session_state.total_levels = 3
 
 
 
 
381
 
382
  # Concept database
383
  CONCEPTS = {
@@ -467,7 +475,7 @@ Characters:
467
  - Villain: A character that creates obstacles (if applicable)
468
 
469
  Game Mechanics:
470
- 1. Move your character using arrow keys
471
  2. Collect stars while avoiding obstacles
472
  3. Reach the goal to win
473
  4. Helper characters appear to teach {concept_list}
@@ -479,7 +487,7 @@ Coding Concepts: This game teaches {concept_list} through:
479
  - Tracking progress with variables
480
  - Managing collections with lists
481
 
482
- Visual Description: Colorful game world with cartoon-style characters, vibrant landscapes, and magical effects.
483
  """
484
 
485
  # Generate game code explanation
@@ -501,80 +509,6 @@ As you play the game, think about:
501
  The code brings your story to life in a fun game world!
502
  """
503
 
504
- # Generate game preview visualization
505
- def generate_game_preview(story):
506
- """Generate a visual preview of the game"""
507
- try:
508
- # Extract keywords for theme
509
- theme = "space" if "space" in story.lower() else "jungle" if "jungle" in story.lower() else "fantasy"
510
-
511
- # Create a simple visualization
512
- fig, ax = plt.subplots(figsize=(10, 6))
513
-
514
- if theme == "space":
515
- bg_color = '#0B0B2B'
516
- player_color = '#8A2BE2'
517
- goal_color = '#FFD700'
518
- obstacle_color = '#9370DB'
519
- title = "Space Adventure"
520
- elif theme == "jungle":
521
- bg_color = '#143D2C'
522
- player_color = '#8A2BE2'
523
- goal_color = '#FFD700'
524
- obstacle_color = '#6A5ACD'
525
- title = "Jungle Adventure"
526
- else:
527
- bg_color = '#3A015C'
528
- player_color = '#8A2BE2'
529
- goal_color = '#FFD700'
530
- obstacle_color = '#9370DB'
531
- title = "Fantasy Quest"
532
-
533
- ax.set_facecolor(bg_color)
534
- ax.set_xlim(0, 10)
535
- ax.set_ylim(0, 6)
536
-
537
- # Draw game elements
538
- ax.text(5, 5, title, fontsize=20, ha='center', color='white')
539
- ax.plot([1, 9], [1, 1], 'w-', linewidth=2) # Ground
540
-
541
- # Player character
542
- ax.plot(2, 2, 'o', markersize=15, color=player_color)
543
- ax.text(2, 2.7, 'You', ha='center', color='white', fontsize=12)
544
-
545
- # Goal
546
- ax.plot(8, 2, 'o', markersize=12, color=goal_color)
547
- ax.text(8, 2.7, 'Goal', ha='center', color='white', fontsize=12)
548
-
549
- # Obstacles
550
- for i in range(3):
551
- x = random.uniform(3, 7)
552
- y = random.uniform(1.5, 2.5)
553
- ax.plot(x, y, 's', markersize=15, color=obstacle_color)
554
- ax.text(x, y+0.4, 'Obstacle', ha='center', color='white', fontsize=8)
555
-
556
- # Stars
557
- for i in range(3):
558
- x = random.uniform(2.5, 7.5)
559
- y = random.uniform(1.2, 2.8)
560
- ax.plot(x, y, '*', markersize=15, color='yellow')
561
- ax.text(x, y+0.4, 'Star', ha='center', color='white', fontsize=8)
562
-
563
- # Path
564
- ax.plot([2, 8], [2, 2], 'y--', linewidth=1, alpha=0.5)
565
-
566
- ax.axis('off')
567
- ax.set_title("Game Preview", fontsize=16, color='white')
568
-
569
- # Save to bytes
570
- buf = io.BytesIO()
571
- plt.savefig(buf, format='png', dpi=100, bbox_inches='tight', facecolor=bg_color)
572
- buf.seek(0)
573
- return buf
574
- except Exception as e:
575
- st.error(f"Preview generation error: {str(e)}")
576
- return None
577
-
578
  def reset_game_state():
579
  st.session_state.game_state = {
580
  "player_pos": [0, 0],
@@ -629,10 +563,12 @@ def move_player(direction):
629
  if new_pos == goal_pos:
630
  state["score"] += 20
631
  state["game_over"] = True
 
632
  # Check for star collection
633
  elif new_pos in stars:
634
  state["score"] += 5
635
  state["stars"].remove(new_pos)
 
636
 
637
  st.session_state.game_state = state
638
 
@@ -716,8 +652,6 @@ def create_playable_game():
716
 
717
  # Next level button
718
  if state["game_over"]:
719
- st.balloons()
720
- st.success(f"🎉 You won! Final Score: {state['score']} in {state['moves']} moves!")
721
  if st.session_state.current_level < st.session_state.total_levels:
722
  if st.button("Next Level →", use_container_width=True):
723
  st.session_state.current_level += 1
@@ -727,16 +661,6 @@ def create_playable_game():
727
  # Theme customizer section
728
  def theme_customizer():
729
  """Theme customization section"""
730
- st.markdown("""
731
- <div class="wave-divider">
732
- <svg viewBox="0 0 1200 120" preserveAspectRatio="none">
733
- <path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" opacity=".25" class="shape-fill"></path>
734
- <path d="M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z" opacity=".5" class="shape-fill"></path>
735
- <path d="M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z" class="shape-fill"></path>
736
- </svg>
737
- </div>
738
- """, unsafe_allow_html=True)
739
-
740
  with st.container():
741
  st.markdown("<div class='theme-customizer'>", unsafe_allow_html=True)
742
  st.markdown("<div class='customizer-title'>🎨 Customize Your Game Theme</div>", unsafe_allow_html=True)
@@ -748,7 +672,7 @@ def theme_customizer():
748
  ["🦸", "👨‍🚀", "🧙‍♂️", "🐱", "🐉", "🦊"],
749
  index=0
750
  )
751
- st.markdown(f"<div class='char-preview floating'>{st.session_state.player_char}</div>", unsafe_allow_html=True)
752
 
753
  with col2:
754
  st.session_state.goal_char = st.selectbox(
@@ -756,7 +680,7 @@ def theme_customizer():
756
  ["🏁", "🏰", "🚩", "🎯", "🔑"],
757
  index=0
758
  )
759
- st.markdown(f"<div class='char-preview floating'>{st.session_state.goal_char}</div>", unsafe_allow_html=True)
760
 
761
  with col3:
762
  st.session_state.obstacle_char = st.selectbox(
@@ -764,31 +688,31 @@ def theme_customizer():
764
  ["🪨", "🌵", "🔥", "🌊", "🌳"],
765
  index=0
766
  )
767
- st.markdown(f"<div class='char-preview floating'>{st.session_state.obstacle_char}</div>", unsafe_allow_html=True)
768
 
769
- st.session_state.current_level = st.slider(
 
770
  "Select Difficulty Level",
771
- 1, 5, st.session_state.current_level
 
772
  )
773
 
774
  st.markdown("</div>", unsafe_allow_html=True)
775
-
776
- st.markdown("""
777
- <div class="wave-divider">
778
- <svg viewBox="0 0 1200 120" preserveAspectRatio="none">
779
- <path d="M0,0V46.29c47.79,22.2,103.59,32.17,158,28,70.36-5.37,136.33-33.31,206.8-37.5C438.64,32.43,512.34,53.67,583,72.05c69.27,18,138.3,24.88,209.4,13.08,36.15-6,69.85-17.84,104.45-29.34C989.49,25,1113-14.29,1200,52.47V0Z" opacity=".25" class="shape-fill"></path>
780
- <path d="M0,0V15.81C13,36.92,27.64,56.86,47.69,72.05,99.41,111.27,165,111,224.58,91.58c31.15-10.15,60.09-26.07,89.67-39.8,40.92-19,84.73-46,130.83-49.67,36.26-2.85,70.9,9.42,98.6,31.56,31.77,25.39,62.32,62,103.63,73,40.44,10.79,81.35-6.69,119.13-24.28s75.16-39,116.92-43.05c59.73-5.85,113.28,22.88,168.9,38.84,30.2,8.66,59,6.17,87.09-7.5,22.43-10.89,48-26.93,60.65-49.24V0Z" opacity=".5" class="shape-fill"></path>
781
- <path d="M0,0V5.63C149.93,59,314.09,71.32,475.83,42.57c43-7.64,84.23-20.12,127.61-26.46,59-8.63,112.48,12.24,165.56,35.4C827.93,77.22,886,95.24,951.2,90c86.53-7,172.46-45.71,248.8-84.81V0Z" class="shape-fill"></path>
782
- </svg>
783
- </div>
784
- """, unsafe_allow_html=True)
785
 
786
  # Main application function
787
  def main():
788
  init_session_state()
789
 
790
  st.title("🎮 StoryCoder - Play & Learn Coding!")
791
- st.markdown("<div class='typewriter'><h2>Turn stories into games, and games into coding skills!</h2></div>",
792
  unsafe_allow_html=True)
793
 
794
  # Theme customizer
@@ -801,13 +725,16 @@ def main():
801
  if st.button("📖 Create Story", use_container_width=True):
802
  st.session_state.active_tab = "story"
803
  with col2:
804
- if st.button("🎮 Play Game", use_container_width=True):
 
805
  st.session_state.active_tab = "game"
806
  with col3:
807
- if st.button("🔍 Concepts", use_container_width=True):
 
808
  st.session_state.active_tab = "concepts"
809
  with col4:
810
- if st.button("💻 Game Code", use_container_width=True):
 
811
  st.session_state.active_tab = "code"
812
  with col5:
813
  if st.button("🔄 New Story", use_container_width=True):
@@ -816,20 +743,60 @@ def main():
816
  st.session_state.game_scenario = ""
817
  st.session_state.game_code = ""
818
  st.session_state.game_explanation = ""
819
- st.session_state.game_preview = None
820
  st.session_state.active_tab = "story"
821
  reset_game_state()
 
822
  st.markdown('</div>', unsafe_allow_html=True)
823
 
824
  # Story creation tab
825
  if st.session_state.active_tab == "story":
826
  with st.container():
827
  st.header("📖 Create Your Story")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
828
  st.write("Write a short story (2-5 sentences) and I'll turn it into a playable game!")
829
 
830
  story = st.text_area(
831
  "Your story:",
832
- height=200,
833
  placeholder="Once upon a time, a brave knight had to collect 5 magical stars in a castle...",
834
  value=st.session_state.story,
835
  key="story_input"
@@ -855,41 +822,34 @@ def main():
855
  story, st.session_state.concepts, st.session_state.game_scenario
856
  )
857
 
858
- with st.spinner("🖼️ Generating game preview..."):
859
- st.session_state.game_preview = generate_game_preview(story)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
860
 
861
  reset_game_state()
862
  st.session_state.active_tab = "game"
863
  st.session_state.loading = False
 
864
  st.rerun()
865
-
866
- # Show examples
867
- st.subheader("✨ Story Examples")
868
- col1, col2, col3 = st.columns(3)
869
- example_images = {
870
- "Space Explorer": "https://images.unsplash.com/photo-1462331940025-496dfbfc7564?w=500",
871
- "Jungle Adventure": "https://images.unsplash.com/photo-1546182990-dffeafbe841d?w=500",
872
- "Dragon Quest": "https://images.unsplash.com/photo-1541414779316-9564c1f85944?w=500"
873
- }
874
-
875
- with col1:
876
- st.caption("Space Explorer")
877
- st.code('"An astronaut needs to collect 3 stars while avoiding asteroids"', language="text")
878
- st.image(example_images["Space Explorer"],
879
- use_container_width=True,
880
- caption="Space Explorer Game")
881
- with col2:
882
- st.caption("Jungle Adventure")
883
- st.code('"A monkey swings through trees to collect bananas before sunset"', language="text")
884
- st.image(example_images["Jungle Adventure"],
885
- use_container_width=True,
886
- caption="Jungle Adventure Game")
887
- with col3:
888
- st.caption("Dragon Quest")
889
- st.code('"A dragon flies through clouds to collect magic crystals"', language="text")
890
- st.image(example_images["Dragon Quest"],
891
- use_container_width=True,
892
- caption="Dragon Quest Game")
893
 
894
  # Game tab
895
  elif st.session_state.active_tab == "game":
@@ -904,14 +864,6 @@ def main():
904
  st.subheader("🌟 Game Scenario")
905
  st.markdown(f'<div class="game-card">{st.session_state.game_scenario}</div>', unsafe_allow_html=True)
906
 
907
- # Display game preview
908
- st.subheader("🖼️ Game Preview")
909
- if st.session_state.game_preview:
910
- st.image(st.session_state.game_preview, use_container_width=True)
911
- else:
912
- st.info("Game preview visualization")
913
- st.image("https://images.unsplash.com/photo-1542751110-97427bbecf20?w=500", use_container_width=True)
914
-
915
  # Playable game
916
  create_playable_game()
917
 
@@ -931,16 +883,26 @@ def main():
931
  if not st.session_state.concepts:
932
  st.warning("No concepts detected in your story! Try adding words like '3 times', 'if', or 'collect'.")
933
  else:
934
- # Concept selector
935
- selected_concept = st.selectbox(
936
- "Select a concept to explore:",
937
- st.session_state.concepts,
938
- format_func=lambda x: CONCEPTS[x]["name"]
939
- )
 
 
 
 
 
 
 
 
 
 
940
 
941
  # Show explanation for selected concept
942
- if selected_concept:
943
- details = CONCEPTS[selected_concept]
944
  st.markdown(f"""
945
  <div class="concept-card" style="border-left: 5px solid {details['color']};">
946
  <div style="display:flex; align-items:center; gap:15px;">
@@ -952,6 +914,8 @@ def main():
952
  <pre style="background:#f0f0f0; padding:10px; border-radius:8px;">{details['example']}</pre>
953
  </div>
954
  """, unsafe_allow_html=True)
 
 
955
 
956
  if st.button("See the Game Code", use_container_width=True):
957
  st.session_state.active_tab = "code"
@@ -962,169 +926,15 @@ def main():
962
  st.header("💻 Game Code")
963
  st.write("Here's the Python code for your game. Download it and run on your computer!")
964
 
965
- # Generate simple game code
966
- if st.session_state.story and st.session_state.concepts:
967
- # Extract keywords from story
968
- keywords = re.findall(r'\b\w{4,}\b', st.session_state.story)[:3]
969
- player_char = keywords[0].capitalize() if keywords else "Hero"
970
- collect_item = keywords[1] if len(keywords) > 1 else "star"
971
- obstacle = keywords[2] if len(keywords) > 2 else "rock"
972
-
973
- # Get concept emojis
974
- concept_emojis = "".join([CONCEPTS[c]['emoji'] for c in st.session_state.concepts])
975
-
976
- game_code = f"""
977
- # {player_char}'s Adventure: {st.session_state.story[:20]}...
978
- # Teaches: {concept_emojis} {", ".join([CONCEPTS[c]['name'] for c in st.session_state.concepts])}
979
-
980
- import pygame
981
- import random
982
- import sys
983
-
984
- # Initialize pygame
985
- pygame.init()
986
-
987
- # Game setup
988
- WIDTH, HEIGHT = 800, 600
989
- screen = pygame.display.set_mode((WIDTH, HEIGHT))
990
- pygame.display.set_caption("{player_char}'s Adventure")
991
- clock = pygame.time.Clock()
992
-
993
- # Colors
994
- BACKGROUND = (230, 230, 250) # Light purple
995
- PLAYER_COLOR = (138, 43, 226) # Purple
996
- GOAL_COLOR = (255, 215, 0) # Gold
997
- OBSTACLE_COLOR = (147, 112, 219) # Medium purple
998
- TEXT_COLOR = (75, 0, 130) # Indigo
999
- STAR_COLOR = (255, 215, 0) # Gold
1000
-
1001
- # Player setup
1002
- player_size = 40
1003
- player_x = 100
1004
- player_y = HEIGHT // 2
1005
- player_speed = 5
1006
-
1007
- # Goal setup
1008
- goal_size = 30
1009
- goal_x = WIDTH - 150
1010
- goal_y = HEIGHT // 2
1011
-
1012
- # Variables concept: Tracking score
1013
- score = 0
1014
- font = pygame.font.SysFont(None, 36)
1015
-
1016
- # List concept: Creating obstacles
1017
- obstacles = []
1018
- for i in range(5):
1019
- obstacles.append([
1020
- random.randint(200, WIDTH - 100),
1021
- random.randint(50, HEIGHT - 100),
1022
- random.randint(30, 70),
1023
- random.randint(20, 50)
1024
- ])
1025
-
1026
- # List concept: Creating stars
1027
- stars = []
1028
- for i in range(5):
1029
- stars.append([
1030
- random.randint(100, WIDTH - 100),
1031
- random.randint(50, HEIGHT - 100),
1032
- 20
1033
- ])
1034
-
1035
- # Game loop
1036
- running = True
1037
- while running:
1038
- # Event handling
1039
- for event in pygame.event.get():
1040
- if event.type == pygame.QUIT:
1041
- running = False
1042
-
1043
- # Player movement
1044
- keys = pygame.key.get_pressed()
1045
- if keys[pygame.K_UP] or keys[pygame.K_w]:
1046
- player_y -= player_speed
1047
- if keys[pygame.K_DOWN] or keys[pygame.K_s]:
1048
- player_y += player_speed
1049
- if keys[pygame.K_LEFT] or keys[pygame.K_a]:
1050
- player_x -= player_speed
1051
- if keys[pygame.K_RIGHT] or keys[pygame.K_d]:
1052
- player_x += player_speed
1053
-
1054
- # Boundary checking
1055
- player_x = max(0, min(WIDTH - player_size, player_x))
1056
- player_y = max(0, min(HEIGHT - player_size, player_y))
1057
-
1058
- # Collision detection with goal
1059
- player_rect = pygame.Rect(player_x, player_y, player_size, player_size)
1060
- goal_rect = pygame.Rect(goal_x, goal_y, goal_size, goal_size)
1061
-
1062
- # Conditional concept: Check for collision
1063
- if player_rect.colliderect(goal_rect):
1064
- # Function concept: Increase score
1065
- score += 10
1066
- # Move goal to new position
1067
- goal_x = random.randint(100, WIDTH - 100)
1068
- goal_y = random.randint(50, HEIGHT - 100)
1069
-
1070
- # Collision detection with stars
1071
- for star in stars[:]:
1072
- star_rect = pygame.Rect(star[0], star[1], star[2], star[2])
1073
- if player_rect.colliderect(star_rect):
1074
- score += 5
1075
- stars.remove(star)
1076
-
1077
- # Drawing
1078
- screen.fill(BACKGROUND)
1079
-
1080
- # Draw obstacles
1081
- for obstacle in obstacles:
1082
- pygame.draw.rect(screen, OBSTACLE_COLOR,
1083
- (obstacle[0], obstacle[1], obstacle[2], obstacle[3]))
1084
-
1085
- # Draw stars
1086
- for star in stars:
1087
- pygame.draw.circle(screen, STAR_COLOR,
1088
- (star[0] + star[2]//2, star[1] + star[2]//2), star[2]//2)
1089
-
1090
- # Draw player and goal
1091
- pygame.draw.rect(screen, PLAYER_COLOR,
1092
- (player_x, player_y, player_size, player_size))
1093
- pygame.draw.circle(screen, GOAL_COLOR,
1094
- (goal_x + goal_size//2, goal_y + goal_size//2), goal_size//2)
1095
-
1096
- # Display score
1097
- score_text = font.render(f"{collect_item.capitalize()}s: {{score}}", True, TEXT_COLOR)
1098
- screen.blit(score_text, (20, 20))
1099
-
1100
- # Display story title
1101
- title_text = font.render(f"{player_char}'s Adventure: {st.session_state.story[:20]}...", True, TEXT_COLOR)
1102
- screen.blit(title_text, (WIDTH // 2 - 150, 20))
1103
-
1104
- # Display concepts
1105
- concepts_text = font.render(f"Teaches: {', '.join([CONCEPTS[c]['name'] for c in st.session_state.concepts])}", True, TEXT_COLOR)
1106
- screen.blit(concepts_text, (20, HEIGHT - 40))
1107
-
1108
- # Display instructions
1109
- help_text = font.render("Arrow keys to move - Collect stars and reach the goal!", True, TEXT_COLOR)
1110
- screen.blit(help_text, (WIDTH // 2 - 200, HEIGHT - 80))
1111
-
1112
- # Update display
1113
- pygame.display.flip()
1114
- clock.tick(60)
1115
-
1116
- pygame.quit()
1117
- sys.exit()
1118
- """
1119
-
1120
  # Display code with syntax highlighting
1121
  st.subheader("Your Game Code")
1122
- st.code(game_code, language="python")
1123
 
1124
  # Download button
1125
  st.download_button(
1126
  label="📥 Download Game Code",
1127
- data=game_code,
1128
  file_name="story_game.py",
1129
  mime="text/python",
1130
  use_container_width=True
@@ -1132,16 +942,18 @@ sys.exit()
1132
 
1133
  # Code explanation
1134
  st.subheader("🧠 Code Explanation")
1135
- st.markdown("""
1136
  <div class="game-card">
1137
- <p>This code creates a game based on your story:</p>
 
1138
  <ul>
1139
  <li><strong>Variables:</strong> Used to track score and positions</li>
1140
  <li><strong>Conditionals:</strong> Check collisions and game rules</li>
1141
- <li><strong>Functions:</strong> pygame functions create the game mechanics</li>
1142
  <li><strong>Loops:</strong> The game loop runs continuously</li>
1143
  <li><strong>Lists:</strong> Store obstacles and collectible stars</li>
1144
  </ul>
 
1145
  </div>
1146
  """, unsafe_allow_html=True)
1147
  else:
@@ -1150,6 +962,9 @@ sys.exit()
1150
  if st.button("Create Another Story!", use_container_width=True):
1151
  st.session_state.active_tab = "story"
1152
  st.rerun()
 
 
 
1153
 
1154
  if __name__ == "__main__":
1155
  main()
 
19
  initial_sidebar_state="expanded"
20
  )
21
 
22
+ # Custom CSS with white background
23
  st.markdown("""
24
  <style>
25
  @import url('https://fonts.googleapis.com/css2?family=Fredoka+One&family=Comic+Neue:wght@700&display=swap');
 
29
  --secondary: #9370DB;
30
  --accent: #FFD700;
31
  --dark: #4B0082;
32
+ --light: #FFFFFF;
33
  --game-blue: #6A5ACD;
34
  --game-purple: #9400D3;
 
 
 
35
  }
36
 
37
  body {
38
+ background: #FFFFFF;
 
 
39
  font-family: 'Comic Neue', cursive;
40
  margin: 0;
41
  padding: 0;
42
  min-height: 100vh;
43
  }
44
 
 
 
 
 
 
 
45
  .stApp {
46
+ background: #FFFFFF;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
47
  }
48
 
49
  .game-card {
50
+ background: rgba(255, 255, 255, 0.95);
51
+ border-radius: 15px;
52
+ padding: 20px;
53
+ box-shadow: 0 4px 16px rgba(138, 43, 226, 0.1);
54
+ border: 1px solid #E0E0E0;
55
+ margin-bottom: 20px;
56
  transition: all 0.3s;
57
  }
58
 
59
  .game-card:hover {
60
+ transform: translateY(-3px);
61
+ box-shadow: 0 8px 16px rgba(138, 43, 226, 0.15);
62
  }
63
 
64
  .header {
65
  color: var(--dark);
66
  font-family: 'Fredoka One', cursive;
 
67
  }
68
 
69
  .concept-card {
70
+ background: rgba(255, 255, 255, 0.95);
71
+ border-radius: 12px;
72
  padding: 15px;
73
  margin: 10px 0;
74
+ border-left: 4px solid var(--accent);
75
+ box-shadow: 0 2px 8px rgba(0,0,0,0.05);
76
  }
77
 
78
  .stButton>button {
79
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
80
  color: white;
81
+ border-radius: 12px;
82
+ padding: 10px 24px;
83
  font-weight: bold;
84
+ font-size: 16px;
85
  border: none;
86
  transition: all 0.3s;
87
  font-family: 'Fredoka One', cursive;
88
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
89
  }
90
 
91
  .stButton>button:hover {
92
+ transform: scale(1.03);
93
+ box-shadow: 0 6px 12px rgba(138, 43, 226, 0.2);
94
  }
95
 
96
  .stTextInput>div>div>input {
97
+ border-radius: 12px;
98
+ padding: 12px;
99
+ border: 2px solid var(--accent);
100
+ font-size: 16px;
101
+ background: rgba(255, 255, 255, 0.95);
102
  }
103
 
104
  .tabs {
105
  display: flex;
106
+ gap: 8px;
107
  margin-bottom: 20px;
108
  overflow-x: auto;
109
+ background: rgba(255, 255, 255, 0.95);
110
+ padding: 8px;
111
+ border-radius: 12px;
112
+ border: 1px solid #E0E0E0;
113
  }
114
 
115
  .tab {
116
+ padding: 10px 20px;
117
+ background: rgba(255, 255, 255, 0.95);
118
+ border-radius: 12px;
119
  cursor: pointer;
120
  font-weight: bold;
121
  white-space: nowrap;
122
  font-family: 'Fredoka One', cursive;
123
+ font-size: 14px;
124
  transition: all 0.3s;
125
  color: var(--dark);
126
+ border: 1px solid #E0E0E0;
127
  }
128
 
129
  .tab.active {
130
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
131
  color: white;
132
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
133
  }
134
 
135
  .game-board {
 
137
  grid-template-columns: repeat(8, 1fr);
138
  grid-template-rows: repeat(8, 1fr);
139
  gap: 4px;
140
+ width: 450px;
141
+ height: 450px;
142
  margin: 0 auto;
143
+ background: #FFFFFF;
144
  padding: 10px;
145
+ border-radius: 12px;
146
+ border: 1px solid #E0E0E0;
147
  }
148
 
149
  .cell {
150
  display: flex;
151
  justify-content: center;
152
  align-items: center;
153
+ border-radius: 6px;
154
+ font-size: 28px;
155
+ background: #FFFFFF;
156
  transition: all 0.2s;
157
  cursor: pointer;
158
+ box-shadow: 0 2px 4px rgba(0,0,0,0.05);
159
+ border: 1px solid #F0F0F0;
160
  }
161
 
162
  .cell:hover {
163
+ transform: scale(1.03);
164
+ background: #F8F8F8;
165
  }
166
 
167
  .player {
168
  background: linear-gradient(45deg, var(--primary), var(--game-blue));
169
  color: white;
170
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
171
  }
172
 
173
  .goal {
174
  background: linear-gradient(45deg, var(--accent), #FFA500);
175
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
176
  }
177
 
178
  .obstacle {
179
  background: linear-gradient(45deg, var(--secondary), #8A2BE2);
180
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
181
  }
182
 
183
  .star {
184
  background: linear-gradient(45deg, #FFD700, #FFA500);
185
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
186
  }
187
 
188
  .portal {
189
  background: linear-gradient(45deg, #9B5DE5, #6A0DAD);
190
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
191
  }
192
 
193
  .game-controls {
194
  display: flex;
195
  justify-content: center;
196
+ gap: 12px;
197
+ margin: 20px 0;
198
  }
199
 
200
  .control-btn {
201
+ width: 60px;
202
+ height: 60px;
203
  border-radius: 50%;
204
  background: linear-gradient(45deg, var(--primary), var(--game-purple));
205
  color: white;
206
  display: flex;
207
  align-items: center;
208
  justify-content: center;
209
+ font-size: 24px;
210
  cursor: pointer;
211
  border: none;
212
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
213
  transition: all 0.2s;
214
  }
215
 
216
  .control-btn:hover {
217
+ transform: scale(1.08);
218
+ box-shadow: 0 6px 12px rgba(0,0,0,0.15);
219
  }
220
 
221
  .score-board {
222
+ background: #FFFFFF;
223
+ border-radius: 12px;
224
+ padding: 12px;
225
  text-align: center;
226
  font-family: 'Fredoka One', cursive;
227
+ font-size: 20px;
228
+ margin: 15px auto;
229
+ width: 280px;
230
+ box-shadow: 0 4px 8px rgba(0,0,0,0.05);
231
+ border: 1px solid #E0E0E0;
232
  }
233
 
234
  .level-indicator {
235
+ background: #FFFFFF;
236
+ border-radius: 12px;
237
+ padding: 8px 16px;
238
  text-align: center;
239
  font-family: 'Fredoka One', cursive;
240
+ font-size: 18px;
241
+ margin: 8px auto;
242
+ width: 180px;
243
+ box-shadow: 0 2px 6px rgba(0,0,0,0.05);
244
+ border: 1px solid #E0E0E0;
245
  }
246
 
247
  .theme-customizer {
248
+ background: #FFFFFF;
249
+ border-radius: 15px;
250
+ padding: 15px;
251
+ margin: 15px 0;
252
+ box-shadow: 0 4px 12px rgba(138, 43, 226, 0.1);
253
+ border: 1px solid #E0E0E0;
254
  }
255
 
256
  .customizer-title {
257
  text-align: center;
258
  font-family: 'Fredoka One', cursive;
259
  color: var(--primary);
260
+ margin-bottom: 15px;
261
+ font-size: 20px;
262
  }
263
 
264
  .char-preview {
265
  text-align: center;
266
+ font-size: 40px;
267
+ margin: 8px 0;
268
  }
269
 
270
  @media (max-width: 768px) {
 
273
  }
274
 
275
  .game-board {
276
+ width: 85vw;
277
+ height: 85vw;
278
  }
279
 
280
  .control-btn {
281
+ width: 50px;
282
+ height: 50px;
283
+ font-size: 20px;
284
  }
285
  }
286
 
287
+ .concept-buttons {
288
+ display: flex;
289
+ flex-wrap: wrap;
290
+ gap: 10px;
291
+ margin: 15px 0;
292
+ }
293
+
294
+ .concept-btn {
295
+ flex: 1 0 calc(33.333% - 10px);
296
+ min-width: 120px;
297
+ padding: 12px;
298
+ border-radius: 10px;
299
+ background: rgba(255, 255, 255, 0.95);
300
+ border: 1px solid #E0E0E0;
301
+ box-shadow: 0 2px 6px rgba(0,0,0,0.05);
302
+ transition: all 0.3s;
303
+ text-align: center;
304
+ cursor: pointer;
305
+ }
306
+
307
+ .concept-btn:hover {
308
+ transform: translateY(-3px);
309
+ box-shadow: 0 4px 8px rgba(138, 43, 226, 0.15);
310
+ border-color: var(--primary);
311
  }
312
 
313
+ .concept-btn.active {
314
+ background: linear-gradient(45deg, var(--primary), var(--game-purple));
315
+ color: white;
316
+ box-shadow: 0 4px 8px rgba(0,0,0,0.1);
317
  }
318
 
319
+ .example-box {
320
+ border: 1px solid #E0E0E0;
321
+ border-radius: 12px;
322
+ padding: 15px;
323
+ margin-bottom: 15px;
324
+ transition: all 0.3s;
325
+ cursor: pointer;
326
  }
327
 
328
+ .example-box:hover {
329
+ transform: translateY(-3px);
330
+ box-shadow: 0 4px 12px rgba(138, 43, 226, 0.1);
331
+ border-color: var(--primary);
332
  }
333
 
334
+ .toast {
335
+ position: fixed;
336
+ bottom: 20px;
337
+ left: 50%;
338
+ transform: translateX(-50%);
339
+ background: rgba(0, 0, 0, 0.8);
340
+ color: white;
341
+ padding: 10px 20px;
342
+ border-radius: 25px;
343
+ z-index: 1000;
344
+ font-family: 'Fredoka One', cursive;
345
+ animation: fadeInOut 2s ease-in-out;
346
+ }
347
+
348
+ @keyframes fadeInOut {
349
+ 0% { opacity: 0; bottom: 0; }
350
+ 20% { opacity: 1; bottom: 20px; }
351
+ 80% { opacity: 1; bottom: 20px; }
352
+ 100% { opacity: 0; bottom: 0; }
353
  }
354
  </style>
355
  """, unsafe_allow_html=True)
 
366
  st.session_state.game_code = ""
367
  if 'game_explanation' not in st.session_state:
368
  st.session_state.game_explanation = ""
 
 
369
  if 'active_tab' not in st.session_state:
370
  st.session_state.active_tab = "story"
371
  if 'loading' not in st.session_state:
 
382
  st.session_state.current_level = 1
383
  if 'total_levels' not in st.session_state:
384
  st.session_state.total_levels = 3
385
+ if 'selected_concept' not in st.session_state:
386
+ st.session_state.selected_concept = None
387
+ if 'toast_message' not in st.session_state:
388
+ st.session_state.toast_message = None
389
 
390
  # Concept database
391
  CONCEPTS = {
 
475
  - Villain: A character that creates obstacles (if applicable)
476
 
477
  Game Mechanics:
478
+ 1. Move your character using arrow keys or buttons
479
  2. Collect stars while avoiding obstacles
480
  3. Reach the goal to win
481
  4. Helper characters appear to teach {concept_list}
 
487
  - Tracking progress with variables
488
  - Managing collections with lists
489
 
490
+ Visual Style: Clean and colorful game world with simple characters.
491
  """
492
 
493
  # Generate game code explanation
 
509
  The code brings your story to life in a fun game world!
510
  """
511
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
512
  def reset_game_state():
513
  st.session_state.game_state = {
514
  "player_pos": [0, 0],
 
563
  if new_pos == goal_pos:
564
  state["score"] += 20
565
  state["game_over"] = True
566
+ st.session_state.toast_message = "🎉 You reached the goal! Well done!"
567
  # Check for star collection
568
  elif new_pos in stars:
569
  state["score"] += 5
570
  state["stars"].remove(new_pos)
571
+ st.session_state.toast_message = "⭐ You collected a star! +5 points"
572
 
573
  st.session_state.game_state = state
574
 
 
652
 
653
  # Next level button
654
  if state["game_over"]:
 
 
655
  if st.session_state.current_level < st.session_state.total_levels:
656
  if st.button("Next Level →", use_container_width=True):
657
  st.session_state.current_level += 1
 
661
  # Theme customizer section
662
  def theme_customizer():
663
  """Theme customization section"""
 
 
 
 
 
 
 
 
 
 
664
  with st.container():
665
  st.markdown("<div class='theme-customizer'>", unsafe_allow_html=True)
666
  st.markdown("<div class='customizer-title'>🎨 Customize Your Game Theme</div>", unsafe_allow_html=True)
 
672
  ["🦸", "👨‍🚀", "🧙‍♂️", "🐱", "🐉", "🦊"],
673
  index=0
674
  )
675
+ st.markdown(f"<div class='char-preview'>{st.session_state.player_char}</div>", unsafe_allow_html=True)
676
 
677
  with col2:
678
  st.session_state.goal_char = st.selectbox(
 
680
  ["🏁", "🏰", "🚩", "🎯", "🔑"],
681
  index=0
682
  )
683
+ st.markdown(f"<div class='char-preview'>{st.session_state.goal_char}</div>", unsafe_allow_html=True)
684
 
685
  with col3:
686
  st.session_state.obstacle_char = st.selectbox(
 
688
  ["🪨", "🌵", "🔥", "🌊", "🌳"],
689
  index=0
690
  )
691
+ st.markdown(f"<div class='char-preview'>{st.session_state.obstacle_char}</div>", unsafe_allow_html=True)
692
 
693
+ # Level selector with visible options
694
+ st.session_state.current_level = st.select_slider(
695
  "Select Difficulty Level",
696
+ options=[1, 2, 3, 4, 5],
697
+ value=st.session_state.current_level
698
  )
699
 
700
  st.markdown("</div>", unsafe_allow_html=True)
701
+
702
+ # Show toast message
703
+ def show_toast():
704
+ """Show a toast message if one exists"""
705
+ if st.session_state.toast_message:
706
+ st.markdown(f"<div class='toast'>{st.session_state.toast_message}</div>", unsafe_allow_html=True)
707
+ # Clear message after showing
708
+ st.session_state.toast_message = None
 
 
709
 
710
  # Main application function
711
  def main():
712
  init_session_state()
713
 
714
  st.title("🎮 StoryCoder - Play & Learn Coding!")
715
+ st.markdown("Turn stories into games, and games into coding skills!",
716
  unsafe_allow_html=True)
717
 
718
  # Theme customizer
 
725
  if st.button("📖 Create Story", use_container_width=True):
726
  st.session_state.active_tab = "story"
727
  with col2:
728
+ if st.button("🎮 Play Game", use_container_width=True,
729
+ disabled=not st.session_state.story or st.session_state.loading):
730
  st.session_state.active_tab = "game"
731
  with col3:
732
+ if st.button("🔍 Concepts", use_container_width=True,
733
+ disabled=not st.session_state.concepts or st.session_state.loading):
734
  st.session_state.active_tab = "concepts"
735
  with col4:
736
+ if st.button("💻 Game Code", use_container_width=True,
737
+ disabled=not st.session_state.game_code or st.session_state.loading):
738
  st.session_state.active_tab = "code"
739
  with col5:
740
  if st.button("🔄 New Story", use_container_width=True):
 
743
  st.session_state.game_scenario = ""
744
  st.session_state.game_code = ""
745
  st.session_state.game_explanation = ""
 
746
  st.session_state.active_tab = "story"
747
  reset_game_state()
748
+ st.session_state.toast_message = "✨ New story started! Create your adventure."
749
  st.markdown('</div>', unsafe_allow_html=True)
750
 
751
  # Story creation tab
752
  if st.session_state.active_tab == "story":
753
  with st.container():
754
  st.header("📖 Create Your Story")
755
+
756
+ # Show examples
757
+ st.subheader("✨ Story Examples")
758
+ col1, col2, col3 = st.columns(3)
759
+ examples = {
760
+ "Space Explorer": "An astronaut needs to collect 3 stars while avoiding asteroids in space.",
761
+ "Jungle Adventure": "A monkey swings through trees to collect bananas before sunset.",
762
+ "Dragon Quest": "A dragon flies through clouds to collect magic crystals in a mystical land."
763
+ }
764
+
765
+ with col1:
766
+ with st.container():
767
+ st.markdown('<div class="example-box">', unsafe_allow_html=True)
768
+ st.subheader("🚀 Space Explorer")
769
+ st.code(examples["Space Explorer"], language="text")
770
+ if st.button("Copy Story", key="copy_space", use_container_width=True):
771
+ st.session_state.story = examples["Space Explorer"]
772
+ st.session_state.toast_message = "🚀 Space story copied to clipboard!"
773
+ st.markdown('</div>', unsafe_allow_html=True)
774
+
775
+ with col2:
776
+ with st.container():
777
+ st.markdown('<div class="example-box">', unsafe_allow_html=True)
778
+ st.subheader("🌿 Jungle Adventure")
779
+ st.code(examples["Jungle Adventure"], language="text")
780
+ if st.button("Copy Story", key="copy_jungle", use_container_width=True):
781
+ st.session_state.story = examples["Jungle Adventure"]
782
+ st.session_state.toast_message = "🌿 Jungle story copied to clipboard!"
783
+ st.markdown('</div>', unsafe_allow_html=True)
784
+
785
+ with col3:
786
+ with st.container():
787
+ st.markdown('<div class="example-box">', unsafe_allow_html=True)
788
+ st.subheader("🐉 Dragon Quest")
789
+ st.code(examples["Dragon Quest"], language="text")
790
+ if st.button("Copy Story", key="copy_dragon", use_container_width=True):
791
+ st.session_state.story = examples["Dragon Quest"]
792
+ st.session_state.toast_message = "🐉 Dragon story copied to clipboard!"
793
+ st.markdown('</div>', unsafe_allow_html=True)
794
+
795
  st.write("Write a short story (2-5 sentences) and I'll turn it into a playable game!")
796
 
797
  story = st.text_area(
798
  "Your story:",
799
+ height=150,
800
  placeholder="Once upon a time, a brave knight had to collect 5 magical stars in a castle...",
801
  value=st.session_state.story,
802
  key="story_input"
 
822
  story, st.session_state.concepts, st.session_state.game_scenario
823
  )
824
 
825
+ # Generate simple game code
826
+ keywords = re.findall(r'\b\w{4,}\b', st.session_state.story)[:3]
827
+ player_char = keywords[0].capitalize() if keywords else "Hero"
828
+ collect_item = keywords[1] if len(keywords) > 1 else "star"
829
+ obstacle = keywords[2] if len(keywords) > 2 else "rock"
830
+
831
+ # Get concept emojis
832
+ concept_emojis = "".join([CONCEPTS[c]['emoji'] for c in st.session_state.concepts])
833
+
834
+ game_code = f"""
835
+ # {player_char}'s Adventure: {st.session_state.story[:20]}...
836
+ # Teaches: {concept_emojis} {", ".join([CONCEPTS[c]['name'] for c in st.session_state.concepts])}
837
+
838
+ import pygame
839
+ import random
840
+ import sys
841
+
842
+ # Game setup and code would go here...
843
+ # This is a simplified representation of the actual game code
844
+ """
845
+
846
+ st.session_state.game_code = game_code
847
 
848
  reset_game_state()
849
  st.session_state.active_tab = "game"
850
  st.session_state.loading = False
851
+ st.session_state.toast_message = "🎮 Game created successfully! Time to play."
852
  st.rerun()
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
853
 
854
  # Game tab
855
  elif st.session_state.active_tab == "game":
 
864
  st.subheader("🌟 Game Scenario")
865
  st.markdown(f'<div class="game-card">{st.session_state.game_scenario}</div>', unsafe_allow_html=True)
866
 
 
 
 
 
 
 
 
 
867
  # Playable game
868
  create_playable_game()
869
 
 
883
  if not st.session_state.concepts:
884
  st.warning("No concepts detected in your story! Try adding words like '3 times', 'if', or 'collect'.")
885
  else:
886
+ # Concept buttons instead of dropdown
887
+ st.markdown("<div class='concept-buttons'>", unsafe_allow_html=True)
888
+
889
+ for concept in st.session_state.concepts:
890
+ details = CONCEPTS[concept]
891
+ is_active = st.session_state.selected_concept == concept
892
+ btn_class = "concept-btn active" if is_active else "concept-btn"
893
+
894
+ if st.button(
895
+ f"{details['emoji']} {details['name']}",
896
+ key=f"concept_{concept}",
897
+ use_container_width=True
898
+ ):
899
+ st.session_state.selected_concept = concept if not is_active else None
900
+
901
+ st.markdown("</div>", unsafe_allow_html=True)
902
 
903
  # Show explanation for selected concept
904
+ if st.session_state.selected_concept:
905
+ details = CONCEPTS[st.session_state.selected_concept]
906
  st.markdown(f"""
907
  <div class="concept-card" style="border-left: 5px solid {details['color']};">
908
  <div style="display:flex; align-items:center; gap:15px;">
 
914
  <pre style="background:#f0f0f0; padding:10px; border-radius:8px;">{details['example']}</pre>
915
  </div>
916
  """, unsafe_allow_html=True)
917
+ else:
918
+ st.info("👆 Click on a concept button above to learn more about it")
919
 
920
  if st.button("See the Game Code", use_container_width=True):
921
  st.session_state.active_tab = "code"
 
926
  st.header("💻 Game Code")
927
  st.write("Here's the Python code for your game. Download it and run on your computer!")
928
 
929
+ if st.session_state.game_code:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
930
  # Display code with syntax highlighting
931
  st.subheader("Your Game Code")
932
+ st.code(st.session_state.game_code, language="python")
933
 
934
  # Download button
935
  st.download_button(
936
  label="📥 Download Game Code",
937
+ data=st.session_state.game_code,
938
  file_name="story_game.py",
939
  mime="text/python",
940
  use_container_width=True
 
942
 
943
  # Code explanation
944
  st.subheader("🧠 Code Explanation")
945
+ st.markdown(f"""
946
  <div class="game-card">
947
+ <p>This code creates a game based on your story: <em>{st.session_state.story[:50]}...</em></p>
948
+ <p>Key programming concepts used:</p>
949
  <ul>
950
  <li><strong>Variables:</strong> Used to track score and positions</li>
951
  <li><strong>Conditionals:</strong> Check collisions and game rules</li>
952
+ <li><strong>Functions:</strong> Organize game mechanics into reusable blocks</li>
953
  <li><strong>Loops:</strong> The game loop runs continuously</li>
954
  <li><strong>Lists:</strong> Store obstacles and collectible stars</li>
955
  </ul>
956
+ <p>To run this game, you'll need to install PyGame and Python on your computer.</p>
957
  </div>
958
  """, unsafe_allow_html=True)
959
  else:
 
962
  if st.button("Create Another Story!", use_container_width=True):
963
  st.session_state.active_tab = "story"
964
  st.rerun()
965
+
966
+ # Show toast messages
967
+ show_toast()
968
 
969
  if __name__ == "__main__":
970
  main()