# app.py - Enhanced Version with Groq API & Playable Games import streamlit as st import os import time import random import json import re import base64 import requests from PIL import Image import io import matplotlib.pyplot as plt import numpy as np from groq import Groq from streamlit_js_eval import streamlit_js_eval # Configure Streamlit page st.set_page_config( page_title="StoryCoder - Learn Coding Through Games", page_icon="🎮", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for game-themed UI with new color scheme st.markdown(""" """, unsafe_allow_html=True) # Initialize session state def init_session_state(): if 'story' not in st.session_state: st.session_state.story = "" if 'concepts' not in st.session_state: st.session_state.concepts = [] if 'game_scenario' not in st.session_state: st.session_state.game_scenario = "" if 'game_code' not in st.session_state: st.session_state.game_code = "" if 'game_explanation' not in st.session_state: st.session_state.game_explanation = "" if 'game_preview' not in st.session_state: st.session_state.game_preview = None if 'active_tab' not in st.session_state: st.session_state.active_tab = "story" if 'loading' not in st.session_state: st.session_state.loading = False if 'game_state' not in st.session_state: st.session_state.game_state = { "player_x": 100, "player_y": 200, "score": 0, "goal_x": 600, "goal_y": 200, "obstacles": [], "game_active": False } if 'groq_api_key' not in st.session_state: st.session_state.groq_api_key = "" # Concept database CONCEPTS = { "loop": { "name": "Loop", "emoji": "🔄", "description": "Loops repeat actions multiple times", "example": "for i in range(5):\n print('Jump!')", "color": "#6A67CE", "game_example": "Repeating jumps to cross a river" }, "conditional": { "name": "Conditional", "emoji": "❓", "description": "Conditionals make decisions in code", "example": "if key_found:\n open_door()\nelse:\n keep_searching()", "color": "#FF7C7C", "game_example": "Choosing paths based on obstacles" }, "function": { "name": "Function", "emoji": "✨", "description": "Functions are reusable blocks of code", "example": "def collect_star():\n score += 1\n play_sound()", "color": "#FDD85D", "game_example": "Creating a jump function used multiple times" }, "variable": { "name": "Variable", "emoji": "📦", "description": "Variables store information", "example": "score = 0\nplayer_health = 100", "color": "#1A8CD8", "game_example": "Tracking collected stars" }, "list": { "name": "List", "emoji": "📝", "description": "Lists store collections of items", "example": "inventory = ['sword', 'shield', 'potion']", "color": "#4CAF50", "game_example": "Storing collected treasures" } } # Initialize Groq client def get_groq_client(): try: if st.session_state.groq_api_key: return Groq(api_key=st.session_state.groq_api_key) return None except: return None # Analyze story and extract concepts def analyze_story(story): """Analyze story and identify programming concepts""" story_lower = story.lower() detected_concepts = [] # Improved concept detection # Check for loops if any(word in story_lower for word in ["times", "repeat", "again", "multiple", "each", "every"]): detected_concepts.append("loop") # Check for conditionals if any(word in story_lower for word in ["if", "when", "unless", "whether", "decide", "choice", "otherwise"]): detected_concepts.append("conditional") # Check for functions if any(word in story_lower for word in ["make", "create", "do", "perform", "cast", "action", "use"]): detected_concepts.append("function") # Check for variables if any(word in story_lower for word in ["is", "has", "set to", "value", "score", "count", "number"]): detected_concepts.append("variable") # Check for lists if any(word in story_lower for word in ["and", "many", "several", "collection", "items", "group", "set of"]): detected_concepts.append("list") return list(set(detected_concepts)) if detected_concepts else ["variable", "function"] # Generate game scenario using Groq def generate_game_scenario(story, concepts): """Generate a game scenario based on the story and concepts""" try: client = get_groq_client() if client: concept_names = [CONCEPTS[c]['name'] for c in concepts] concept_list = ", ".join(concept_names) system_prompt = ( "You are an expert in creating educational games for children aged 6-12. " "Create a simple 3D-style game scenario based on the child's story. " "The game should teach programming concepts through gameplay. " "Structure your response with these sections:\n" "Game Title: ...\n" "Game Objective: ...\n" "Characters: ...\n" "Game Mechanics: ...\n" "Coding Concepts: Explain how these programming concepts are used: " + concept_list + "\n" "Visual Description: Describe the game world visually\n" "Keep it under 200 words and fun for kids." ) response = client.chat.completions.create( model="llama3-70b-8192", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": story} ], temperature=0.8, max_tokens=500 ) return response.choices[0].message.content except Exception as e: st.error(f"Game scenario generation error: {str(e)}") # Fallback template concept_names = [CONCEPTS[c]['name'] for c in concepts] concept_list = ", ".join(concept_names) return f""" Game Title: {story[:15]} Adventure Game Objective: Complete challenges based on your story: {story[:100]}... Characters: - Hero: The main character from your story - Helper: A friendly guide who explains coding concepts - Villain: A character that creates obstacles (if applicable) Game Mechanics: 1. Move your character using arrow keys 2. Collect items mentioned in your story 3. Avoid obstacles and solve puzzles 4. Helper characters appear to teach {concept_list} Coding Concepts: This game teaches {concept_list} through: - Using loops to repeat actions - Making decisions with conditionals - Creating reusable functions - Tracking progress with variables - Managing collections with lists Visual Description: Colorful 3D world with cartoon-style characters, vibrant landscapes, and magical effects. """ # Generate game code explanation def generate_game_explanation(story, concepts, game_scenario): """Generate explanation of game code""" try: client = get_groq_client() if client: concept_names = [CONCEPTS[c]['name'] for c in concepts] concept_list = ", ".join(concept_names) system_prompt = ( "Explain how the game code implements programming concepts in a way " "a child aged 6-12 can understand. Use simple analogies and relate to the story. " "Structure your response with:\n" "Introduction: ...\n" "Concept 1: ... (with example from the game)\n" "Concept 2: ... (with example from the game)\n" "Conclusion: ...\n" "Keep it under 300 words and engaging for kids." ) response = client.chat.completions.create( model="llama3-70b-8192", messages=[ {"role": "system", "content": system_prompt}, {"role": "user", "content": f"Story: {story}\nGame Scenario: {game_scenario}\nConcepts: {concept_list}"} ], temperature=0.7, max_tokens=600 ) return response.choices[0].message.content except Exception as e: st.error(f"Explanation generation error: {str(e)}") # Fallback explanation concept_explanations = "\n".join( [f"- {CONCEPTS[c]['name']}: {CONCEPTS[c]['game_example']}" for c in concepts] ) return f""" In this game based on your story "{story[:20]}...", we use programming concepts to make it work: {concept_explanations} As you play the game, think about: 1. How the game uses these concepts to create challenges 2. How you might change the code to make the game easier or harder The code brings your story to life in a 3D game world! """ # Generate simple game code def generate_game_code(story, concepts): """Generate simple PyGame code for the game""" # Extract keywords from story keywords = re.findall(r'\b\w{4,}\b', story)[:3] player_char = keywords[0].capitalize() if keywords else "Hero" collect_item = keywords[1] if len(keywords) > 1 else "star" obstacle = keywords[2] if len(keywords) > 2 else "rock" # Get concept emojis concept_emojis = "".join([CONCEPTS[c]['emoji'] for c in concepts]) return f""" # {player_char}'s Adventure: {story[:20]}... # Teaches: {concept_emojis} {", ".join([CONCEPTS[c]['name'] for c in concepts])} import pygame import random import sys # Initialize pygame pygame.init() # Game setup WIDTH, HEIGHT = 800, 600 screen = pygame.display.set_mode((WIDTH, HEIGHT)) pygame.display.set_caption("{player_char}'s Adventure") clock = pygame.time.Clock() # Colors BACKGROUND = (230, 240, 255) # Light blue PLAYER_COLOR = (106, 103, 206) # Purple GOAL_COLOR = (253, 216, 93) # Yellow OBSTACLE_COLOR = (255, 124, 124) # Coral TEXT_COLOR = (45, 50, 80) # Dark blue # Player setup player_size = 40 player_x = 100 player_y = HEIGHT // 2 player_speed = 5 # Goal setup goal_size = 30 goal_x = WIDTH - 150 goal_y = HEIGHT // 2 # Variables concept: Tracking score score = 0 font = pygame.font.SysFont(None, 36) # List concept: Creating obstacles obstacles = [] for i in range(5): obstacles.append([ random.randint(200, WIDTH - 100), random.randint(50, HEIGHT - 100), random.randint(30, 70), random.randint(20, 50) ]) # Game loop running = True while running: # Event handling for event in pygame.event.get(): if event.type == pygame.QUIT: running = False # Player movement keys = pygame.key.get_pressed() if keys[pygame.K_UP] or keys[pygame.K_w]: player_y -= player_speed if keys[pygame.K_DOWN] or keys[pygame.K_s]: player_y += player_speed if keys[pygame.K_LEFT] or keys[pygame.K_a]: player_x -= player_speed if keys[pygame.K_RIGHT] or keys[pygame.K_d]: player_x += player_speed # Boundary checking player_x = max(0, min(WIDTH - player_size, player_x)) player_y = max(0, min(HEIGHT - player_size, player_y)) # Collision detection with goal player_rect = pygame.Rect(player_x, player_y, player_size, player_size) goal_rect = pygame.Rect(goal_x, goal_y, goal_size, goal_size) # Conditional concept: Check for collision if player_rect.colliderect(goal_rect): # Function concept: Increase score score += 1 # Move goal to new position goal_x = random.randint(100, WIDTH - 100) goal_y = random.randint(50, HEIGHT - 100) # Drawing screen.fill(BACKGROUND) # Draw obstacles for obstacle in obstacles: pygame.draw.rect(screen, OBSTACLE_COLOR, (obstacle[0], obstacle[1], obstacle[2], obstacle[3])) # Draw player and goal pygame.draw.rect(screen, PLAYER_COLOR, (player_x, player_y, player_size, player_size)) pygame.draw.circle(screen, GOAL_COLOR, (goal_x + goal_size//2, goal_y + goal_size//2), goal_size//2) # Display score score_text = font.render(f"{collect_item.capitalize()}s: {{score}}", True, TEXT_COLOR) screen.blit(score_text, (20, 20)) # Display story title title_text = font.render(f"{player_char}'s Adventure: {story[:20]}...", True, TEXT_COLOR) screen.blit(title_text, (WIDTH // 2 - 150, 20)) # Display concepts concepts_text = font.render(f"Teaches: {', '.join([CONCEPTS[c]['name'] for c in concepts])}", True, TEXT_COLOR) screen.blit(concepts_text, (20, HEIGHT - 40)) # Display instructions help_text = font.render("Arrow keys to move - Collect the yellow circles!", True, TEXT_COLOR) screen.blit(help_text, (WIDTH // 2 - 200, HEIGHT - 80)) # Update display pygame.display.flip() clock.tick(60) pygame.quit() sys.exit() """ # Generate game preview visualization def generate_game_preview(story): """Generate a visual preview of the game""" try: # Extract keywords for theme theme = "space" if "space" in story.lower() else "jungle" if "jungle" in story.lower() else "fantasy" # Create a simple visualization fig, ax = plt.subplots(figsize=(10, 6)) if theme == "space": bg_color = '#0B0B2B' player_color = '#6A67CE' goal_color = '#FDD85D' obstacle_color = '#FF7C7C' title = "Space Adventure" elif theme == "jungle": bg_color = '#143D2C' player_color = '#6A67CE' goal_color = '#FDD85D' obstacle_color = '#D35400' title = "Jungle Adventure" else: bg_color = '#3A015C' player_color = '#6A67CE' goal_color = '#FDD85D' obstacle_color = '#FF7C7C' title = "Fantasy Quest" ax.set_facecolor(bg_color) ax.set_xlim(0, 10) ax.set_ylim(0, 6) # Draw game elements ax.text(5, 5, title, fontsize=20, ha='center', color='white') ax.plot([1, 9], [1, 1], 'w-', linewidth=2) # Ground # Player character ax.plot(2, 2, 'o', markersize=15, color=player_color) ax.text(2, 2.7, 'You', ha='center', color='white', fontsize=12) # Goal ax.plot(8, 2, 'o', markersize=12, color=goal_color) ax.text(8, 2.7, 'Goal', ha='center', color='white', fontsize=12) # Obstacles for i in range(3): x = random.uniform(3, 7) y = random.uniform(1.5, 2.5) ax.plot(x, y, 's', markersize=15, color=obstacle_color) ax.text(x, y+0.4, 'Obstacle', ha='center', color='white', fontsize=8) # Path ax.plot([2, 8], [2, 2], 'y--', linewidth=1, alpha=0.5) ax.axis('off') ax.set_title("Game Preview", fontsize=16, color='white') # Save to bytes buf = io.BytesIO() plt.savefig(buf, format='png', dpi=100, bbox_inches='tight', facecolor=bg_color) buf.seek(0) return buf except Exception as e: st.error(f"Preview generation error: {str(e)}") return None # Create a playable game in the browser def create_playable_game(): """Create an interactive game using Streamlit components""" st.subheader("🎮 Play Your Game in the Browser!") # Initialize game state if 'game_state' not in st.session_state: st.session_state.game_state = { "player_x": 100, "player_y": 200, "score": 0, "goal_x": 600, "goal_y": 200, "obstacles": [ {"x": 300, "y": 150, "w": 80, "h": 30}, {"x": 400, "y": 250, "w": 60, "h": 40}, {"x": 200, "y": 300, "w": 100, "h": 25} ], "game_active": True } state = st.session_state.game_state # Game canvas st.markdown(f"""
pip install pygame
python your_game.py
{details['description']}
In your game: {details['game_example']}
{details['example']}
pip install pygame
my_game.py
python my_game.py