├── Speed Typing Test Python ├── icon.png ├── background.jpg ├── type-speed-open.png ├── sentences.txt └── speed typing.py └── README.md /Speed Typing Test Python/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codecravings/Speed-Typing-Test-Python/HEAD/Speed Typing Test Python/icon.png -------------------------------------------------------------------------------- /Speed Typing Test Python/background.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codecravings/Speed-Typing-Test-Python/HEAD/Speed Typing Test Python/background.jpg -------------------------------------------------------------------------------- /Speed Typing Test Python/type-speed-open.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/codecravings/Speed-Typing-Test-Python/HEAD/Speed Typing Test Python/type-speed-open.png -------------------------------------------------------------------------------- /Speed Typing Test Python/sentences.txt: -------------------------------------------------------------------------------- 1 | Code is like humor. When you have to explain it, it's bad. 2 | When to use iterative development? You should use iterative development only on projects that you want to succeed. 3 | In order to be irreplaceable, one must always be different 4 | Optimism is an occupational hazard of programming: feedback is the treatment. 5 | Before software can be reusable it first has to be usable. 6 | If opportunity doesn't knock, build a door. 7 | The quick brown fox jumps over the lazy dog. 8 | Python is a high-level programming language known for its simplicity and readability. 9 | Machine learning algorithms can identify patterns in large datasets automatically. 10 | Cloud computing has revolutionized how we store and process data. 11 | Artificial intelligence will transform many industries in the coming decades. 12 | Open source software drives innovation and collaboration in technology. 13 | Cybersecurity is crucial for protecting sensitive information online. 14 | Data visualization helps people understand complex information quickly. 15 | Software testing ensures applications work correctly and reliably. 16 | User experience design focuses on creating intuitive and enjoyable interfaces. 17 | DevOps practices streamline software development and deployment processes. 18 | Version control systems track changes and enable collaborative coding. 19 | Algorithms are step-by-step procedures for solving computational problems. 20 | Databases organize and store information for efficient retrieval and analysis. 21 | The internet connects billions of devices worldwide through interconnected networks. 22 | Programming languages provide tools for expressing computational logic and solutions. 23 | Quantum computing promises to solve complex problems exponentially faster than classical computers. 24 | Blockchain technology enables secure, decentralized transactions without intermediaries. 25 | Neural networks mimic brain function to process and learn from data patterns. 26 | API development connects different software applications seamlessly. 27 | Responsive web design adapts interfaces to work across all device sizes. 28 | Git version control revolutionized collaborative software development workflows. 29 | Microservices architecture breaks large applications into smaller, manageable components. 30 | Containerization technologies like Docker simplify application deployment and scaling. 31 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🚀 TYPING TEST: FROM ZERO TO KEYBOARD HERO 2 | 3 | *Warning: Side effects may include uncontrollable urge to correct other people's typos and excessive use of keyboard shortcuts in real life.* 4 | 5 | ## 🎭 What Just Happened Here? 6 | 7 | Your innocent little typing test just got a **MASSIVE GLOW-UP**! 💅 8 | 9 | We took your humble speed test and gave it more features than a Swiss Army knife at a camping convention. It's like we fed it performance-enhancing vitamins and sent it to coding bootcamp. 10 | 11 | ### 🧬 **Code Evolution (Survival of the Fittest)** 12 | - **Before**: Spaghetti code that would make Italians cry 13 | - **After**: Clean, organized architecture that Marie Kondo would approve of 14 | - **New**: Fancy enums because apparently we're sophisticated now 15 | - **Bonus**: Error handling that actually handles errors (revolutionary!) 16 | 17 | ### 🎮 **Gameplay That'll Make You Feel Like a Hacker** 18 | - **Real-time Rainbow Highlighting** 🌈 19 | - Green = "You're doing great, sweetie!" 💚 20 | - Red = "Oopsie daisy, try again!" ❤️ 21 | - Yellow = "You are HERE (like a mall map)" 💛 22 | - Gray = "Patiently waiting their turn" 🤍 23 | 24 | - **Smart Completion** (Because Quitting is for Quitters) 25 | - Type everything like a perfectionist, OR 26 | - Wimp out at 80% completion with ENTER (we won't judge... much) 27 | - Live stats because instant gratification is everything 28 | 29 | ### 📊 **Statistics That Would Make a Data Scientist Weep** 30 | - **Forever Memory** (stored in `typing_stats.json`) 31 | - Your best WPM (to brag about at parties) 32 | - Accuracy records (for when you peaked in life) 33 | - Game history going back 50 sessions (because who doesn't love nostalgia?) 34 | - Timestamps (to pinpoint exactly when you gave up) 35 | 36 | - **Results Screen Flex** 💪 37 | - Current performance vs. your legendary past 38 | - Error counting (the hall of shame) 39 | - Personal bests comparison (remember when you were good?) 40 | 41 | ### 🎨 **Themes for Every Mood Disorder** 42 | - **Dark Theme**: For vampires and night owls 🦇 43 | - **Light Theme**: For morning people (ew) ☀️ 44 | - **Neon Theme**: For when you want to feel like you're in Tron 🌟 45 | - **Retro Theme**: For when you miss the good old days 📺 46 | 47 | ### 🎢 **Difficulty Levels (Choose Your Suffering)** 48 | - **Easy**: "My grandma could type this" difficulty 49 | - **Medium**: "Respectable human being" level 50 | - **Hard**: "Show-off at the office" mode 51 | - **Expert**: "I have no life but excellent WPM" territory 52 | 53 | ### 🎵 **Sound Effects (Because Silence is Overrated)** 54 | - **Beep Boop Symphony**: 55 | - Happy beeps for success (dopamine delivery system) 56 | - Sad beeps for failures (shame bell) 57 | - Victory fanfare for completion (your moment of glory) 58 | - **Generated on-the-fly** because we're fancy like that 59 | - **Toggle-able** for when your coworkers complain 60 | 61 | ### 📚 **30+ Sentences That'll Educate Your Fingers** 62 | From basic "quick brown fox" to "quantum computing will revolutionize blockchain AI neural networks" (because we live in the future, apparently) 63 | 64 | ### ⌨️ **Keyboard Shortcuts (For the Impatient)** 65 | - **ESC**: "I quit!" button (rage quit friendly) 66 | - **ENTER**: "Good enough!" completion 67 | - **F1**: "Surprise me!" settings roulette 68 | - **F2**: "Make it pretty!" theme switcher 69 | - **F3**: "Shh!" sound toggle 70 | - **Backspace**: Actually works now (groundbreaking!) 71 | 72 | ## 🎪 How to Become a Typing Legend 73 | 74 | 1. **Launch**: `python "speed typing.py"` (prepare for greatness) 75 | 2. **Click**: That big obvious text box (it's waiting for you) 76 | 3. **Type**: Like your life depends on it (it doesn't, but pretend) 77 | 4. **Marvel**: At your real-time stats (or cry, we don't judge) 78 | 5. **Finish**: Either completely or wimp out at 80% 79 | 6. **Bask**: In your mediocre/amazing results 80 | 7. **Repeat**: Until you achieve keyboard enlightenment 81 | 82 | ## 🎭 Pro Tips from Reformed Hunt-and-Peckers 83 | 84 | - **Accuracy > Speed**: Unless you're trying to impress teenagers 85 | - **Try all difficulties**: Growth happens outside comfort zones (ugh, motivational quotes) 86 | - **Experiment with themes**: Life's too short for boring colors 87 | - **Check your history**: Marvel at your inconsistency 88 | - **Practice regularly**: Or don't, we're not your mom 89 | 90 | ## 🔧 Requirements (The Boring Stuff) 91 | 92 | - Python 3.6+ (because we're not animals) 93 | - Pygame 2.0+ (for the fancy graphics) 94 | - Working fingers (negotiable) 95 | - Sense of humor (clearly optional) 96 | 97 | ## 🎨 Automatic Everything 98 | 99 | The game saves your: 100 | - Stats (for eternal bragging rights) 101 | - Preferences (because you're special) 102 | - History (your legacy of typos) 103 | - Settings (convenience is king) 104 | 105 | **Warning**: May cause addiction to typing tests and an inexplicable urge to measure everything in WPM. 106 | 107 | --- 108 | 109 | **Now go forth and clickety-clack your way to glory!** ⌨️👑 110 | 111 | *P.S. If you reach 100+ WPM, please consider applying to be a court stenographer or professional keyboard tester.* 112 | -------------------------------------------------------------------------------- /Speed Typing Test Python/speed typing.py: -------------------------------------------------------------------------------- 1 | import pygame 2 | from pygame.locals import * 3 | import sys 4 | import time 5 | import random 6 | import json 7 | import os 8 | from datetime import datetime 9 | from enum import Enum 10 | 11 | 12 | class Difficulty(Enum): 13 | EASY = "easy" 14 | MEDIUM = "medium" 15 | HARD = "hard" 16 | EXPERT = "expert" 17 | 18 | class Theme(Enum): 19 | DARK = "dark" 20 | LIGHT = "light" 21 | NEON = "neon" 22 | RETRO = "retro" 23 | 24 | class TypingGame: 25 | 26 | def __init__(self): 27 | # Screen dimensions 28 | self.w = 1200 29 | self.h = 700 30 | 31 | # Game state 32 | self.reset = True 33 | self.active = False 34 | self.input_text = '' 35 | self.target_text = '' 36 | self.time_start = 0 37 | self.total_time = 0 38 | self.accuracy = 0 39 | self.wpm = 0 40 | self.end = False 41 | self.char_index = 0 42 | 43 | # Settings 44 | self.difficulty = Difficulty.MEDIUM 45 | self.theme = Theme.DARK 46 | self.sound_enabled = True 47 | 48 | # Statistics 49 | self.stats = self.load_stats() 50 | self.current_errors = 0 51 | self.correct_chars = 0 52 | 53 | # Colors - will be set by theme 54 | self.colors = {} 55 | self.set_theme_colors() 56 | 57 | # Real-time feedback 58 | self.char_colors = [] 59 | 60 | # Initialize pygame 61 | pygame.init() 62 | 63 | # Load images with error handling 64 | try: 65 | self.open_img = pygame.image.load('type-speed-open.png') 66 | self.open_img = pygame.transform.scale(self.open_img, (self.w, self.h)) 67 | 68 | self.bg = pygame.image.load('background.jpg') 69 | self.bg = pygame.transform.scale(self.bg, (self.w, self.h)) 70 | except pygame.error: 71 | self.open_img = None 72 | self.bg = None 73 | 74 | # Sound system disabled for compatibility 75 | self.sound_enabled = False 76 | 77 | self.screen = pygame.display.set_mode((self.w, self.h)) 78 | pygame.display.set_caption('Advanced Speed Typing Test') 79 | 80 | # Fonts 81 | self.fonts = { 82 | 'large': pygame.font.Font(None, 48), 83 | 'medium': pygame.font.Font(None, 32), 84 | 'small': pygame.font.Font(None, 24), 85 | 'tiny': pygame.font.Font(None, 18) 86 | } 87 | 88 | 89 | def play_sound(self, sound_name): 90 | """Sound system disabled for compatibility""" 91 | pass 92 | 93 | def set_theme_colors(self): 94 | """Set colors based on current theme""" 95 | themes = { 96 | Theme.DARK: { 97 | 'bg': (20, 20, 25), 98 | 'text': (240, 240, 240), 99 | 'correct': (100, 255, 100), 100 | 'error': (255, 100, 100), 101 | 'cursor': (255, 255, 100), 102 | 'input_bg': (40, 40, 50), 103 | 'input_border': (100, 100, 120), 104 | 'button': (60, 60, 80), 105 | 'button_hover': (80, 80, 100) 106 | }, 107 | Theme.LIGHT: { 108 | 'bg': (250, 250, 255), 109 | 'text': (40, 40, 50), 110 | 'correct': (50, 150, 50), 111 | 'error': (200, 50, 50), 112 | 'cursor': (100, 100, 200), 113 | 'input_bg': (255, 255, 255), 114 | 'input_border': (200, 200, 220), 115 | 'button': (220, 220, 240), 116 | 'button_hover': (200, 200, 220) 117 | }, 118 | Theme.NEON: { 119 | 'bg': (10, 0, 20), 120 | 'text': (0, 255, 255), 121 | 'correct': (0, 255, 100), 122 | 'error': (255, 0, 100), 123 | 'cursor': (255, 255, 0), 124 | 'input_bg': (20, 0, 40), 125 | 'input_border': (100, 0, 200), 126 | 'button': (50, 0, 100), 127 | 'button_hover': (80, 0, 160) 128 | } 129 | } 130 | self.colors = themes.get(self.theme, themes[Theme.DARK]) 131 | 132 | def load_stats(self): 133 | """Load statistics from file""" 134 | try: 135 | with open('typing_stats.json', 'r') as f: 136 | return json.load(f) 137 | except (FileNotFoundError, json.JSONDecodeError): 138 | return { 139 | 'games_played': 0, 140 | 'best_wpm': 0, 141 | 'best_accuracy': 0, 142 | 'total_time': 0, 143 | 'history': [] 144 | } 145 | 146 | def save_stats(self): 147 | """Save statistics to file""" 148 | with open('typing_stats.json', 'w') as f: 149 | json.dump(self.stats, f, indent=2) 150 | 151 | def draw_text(self, msg, pos, font_size='medium', color=None, center=True): 152 | """Enhanced text drawing with better positioning""" 153 | if color is None: 154 | color = self.colors['text'] 155 | 156 | font = self.fonts[font_size] 157 | text = font.render(msg, True, color) 158 | 159 | if center: 160 | if isinstance(pos, tuple) and len(pos) == 2: 161 | text_rect = text.get_rect(center=pos) 162 | else: 163 | text_rect = text.get_rect(center=(self.w // 2, pos)) 164 | else: 165 | text_rect = text.get_rect(topleft=pos) 166 | 167 | self.screen.blit(text, text_rect) 168 | return text_rect 169 | 170 | def get_text_by_difficulty(self): 171 | """Get text based on difficulty level""" 172 | try: 173 | with open('sentences.txt', 'r') as f: 174 | sentences = [line.strip() for line in f if line.strip()] 175 | except FileNotFoundError: 176 | sentences = [ 177 | "The quick brown fox jumps over the lazy dog.", 178 | "Programming is the art of telling another human what one wants the computer to do.", 179 | "In order to understand recursion, you must first understand recursion." 180 | ] 181 | 182 | if self.difficulty == Difficulty.EASY: 183 | # Return shorter, simpler sentences 184 | easy_sentences = [s for s in sentences if len(s) < 50 and s.count(',') <= 1] 185 | return random.choice(easy_sentences if easy_sentences else sentences[:3]) 186 | elif self.difficulty == Difficulty.MEDIUM: 187 | # Return medium length sentences 188 | return random.choice(sentences) 189 | elif self.difficulty == Difficulty.HARD: 190 | # Return longer sentences or combine multiple 191 | if len(sentences) > 1 and random.random() < 0.5: 192 | return f"{random.choice(sentences)} {random.choice(sentences)}" 193 | return random.choice(sentences) 194 | else: # EXPERT 195 | # Return very challenging text with numbers and symbols 196 | expert_additions = [ 197 | "Programming languages: Python (2.7, 3.8+), JavaScript (ES6), C++ (ISO/IEC 14882:2017).", 198 | "Special characters: @#$%^&*()_+-=[]{}|;':,.<>?/~`!", 199 | "Mixed case: CamelCase, snake_case, kebab-case, PascalCase, SCREAMING_SNAKE_CASE." 200 | ] 201 | if random.random() < 0.3: 202 | return random.choice(expert_additions) 203 | return random.choice(sentences) 204 | 205 | def calculate_results(self): 206 | """Calculate typing results with improved accuracy""" 207 | if self.end: 208 | return 209 | 210 | self.total_time = time.time() - self.time_start 211 | 212 | # More accurate accuracy calculation 213 | if len(self.target_text) > 0: 214 | self.accuracy = (self.correct_chars / len(self.target_text)) * 100 215 | else: 216 | self.accuracy = 0 217 | 218 | # WPM calculation (standard: 5 characters = 1 word) 219 | if self.total_time > 0: 220 | self.wpm = (len(self.input_text) / 5) * (60 / self.total_time) 221 | else: 222 | self.wpm = 0 223 | 224 | self.end = True 225 | 226 | # Update statistics 227 | self.update_stats() 228 | 229 | def update_stats(self): 230 | """Update and save statistics""" 231 | self.stats['games_played'] += 1 232 | self.stats['total_time'] += self.total_time 233 | 234 | if self.wpm > self.stats['best_wpm']: 235 | self.stats['best_wpm'] = self.wpm 236 | 237 | if self.accuracy > self.stats['best_accuracy']: 238 | self.stats['best_accuracy'] = self.accuracy 239 | 240 | # Add to history 241 | game_record = { 242 | 'date': datetime.now().isoformat(), 243 | 'wpm': round(self.wpm, 1), 244 | 'accuracy': round(self.accuracy, 1), 245 | 'time': round(self.total_time, 1), 246 | 'difficulty': self.difficulty.value, 247 | 'errors': self.current_errors 248 | } 249 | 250 | self.stats['history'].append(game_record) 251 | 252 | # Keep only last 50 games 253 | if len(self.stats['history']) > 50: 254 | self.stats['history'] = self.stats['history'][-50:] 255 | 256 | self.save_stats() 257 | 258 | def draw_results_screen(self): 259 | """Draw comprehensive results screen""" 260 | self.screen.fill(self.colors['bg']) 261 | 262 | # Title 263 | self.draw_text("Test Complete!", (self.w // 2, 100), 'large', self.colors['text']) 264 | 265 | # Main results 266 | y_pos = 200 267 | results = [ 268 | f"WPM: {self.wpm:.1f}", 269 | f"Accuracy: {self.accuracy:.1f}%", 270 | f"Time: {self.total_time:.1f}s", 271 | f"Errors: {self.current_errors}" 272 | ] 273 | 274 | for result in results: 275 | color = self.colors['correct'] if 'WPM' in result or 'Accuracy' in result else self.colors['text'] 276 | self.draw_text(result, (self.w // 2, y_pos), 'medium', color) 277 | y_pos += 40 278 | 279 | # Personal bests 280 | y_pos += 30 281 | self.draw_text("Personal Bests:", (self.w // 2, y_pos), 'medium', self.colors['text']) 282 | y_pos += 40 283 | 284 | best_texts = [ 285 | f"Best WPM: {self.stats['best_wpm']:.1f}", 286 | f"Best Accuracy: {self.stats['best_accuracy']:.1f}%", 287 | f"Games Played: {self.stats['games_played']}" 288 | ] 289 | 290 | for text in best_texts: 291 | self.draw_text(text, (self.w // 2, y_pos), 'small', self.colors['text']) 292 | y_pos += 30 293 | 294 | # Buttons 295 | self.draw_button("Play Again", (self.w // 2 - 100, self.h - 100), (200, 50)) 296 | self.draw_button("Settings", (self.w // 2 + 120, self.h - 100), (120, 50)) 297 | 298 | def draw_button(self, text, pos, size, hover=False): 299 | """Draw a modern button""" 300 | color = self.colors['button_hover'] if hover else self.colors['button'] 301 | rect = pygame.Rect(pos[0], pos[1], size[0], size[1]) 302 | pygame.draw.rect(self.screen, color, rect, border_radius=10) 303 | pygame.draw.rect(self.screen, self.colors['input_border'], rect, 2, border_radius=10) 304 | 305 | # Center text in button 306 | text_pos = (pos[0] + size[0] // 2, pos[1] + size[1] // 2) 307 | self.draw_text(text, text_pos, 'small', self.colors['text']) 308 | return rect 309 | 310 | def draw_typing_area(self): 311 | """Draw the main typing interface with real-time feedback""" 312 | # Input box 313 | input_rect = pygame.Rect(50, 400, self.w - 100, 60) 314 | pygame.draw.rect(self.screen, self.colors['input_bg'], input_rect, border_radius=10) 315 | pygame.draw.rect(self.screen, self.colors['input_border'], input_rect, 3, border_radius=10) 316 | 317 | # Target text with character-by-character highlighting 318 | self.draw_highlighted_text() 319 | 320 | # Input text 321 | input_surface = self.fonts['medium'].render(self.input_text, True, self.colors['text']) 322 | self.screen.blit(input_surface, (70, 420)) 323 | 324 | # Cursor 325 | if self.active and not self.end: 326 | cursor_x = 70 + input_surface.get_width() 327 | if int(time.time() * 2) % 2: # Blinking cursor 328 | pygame.draw.line(self.screen, self.colors['cursor'], 329 | (cursor_x, 415), (cursor_x, 445), 2) 330 | 331 | # Real-time stats 332 | if self.active and not self.end and self.time_start > 0: 333 | current_time = time.time() - self.time_start 334 | current_wpm = (len(self.input_text) / 5) * (60 / max(current_time, 1)) 335 | current_accuracy = (self.correct_chars / max(len(self.input_text), 1)) * 100 if len(self.input_text) > 0 else 100 336 | 337 | stats_text = f"WPM: {current_wpm:.0f} | Accuracy: {current_accuracy:.0f}% | Time: {current_time:.0f}s" 338 | self.draw_text(stats_text, (self.w // 2, 500), 'small', self.colors['text']) 339 | 340 | def draw_highlighted_text(self): 341 | """Draw target text with character-by-character highlighting""" 342 | if not self.target_text: 343 | return 344 | 345 | font = self.fonts['medium'] 346 | x, y = 70, 300 347 | max_width = self.w - 140 348 | 349 | for i, char in enumerate(self.target_text): 350 | # Determine color based on typing progress 351 | if i < len(self.input_text): 352 | if i < len(self.input_text) and self.input_text[i] == char: 353 | color = self.colors['correct'] 354 | else: 355 | color = self.colors['error'] 356 | elif i == len(self.input_text): 357 | color = self.colors['cursor'] # Current character 358 | else: 359 | color = self.colors['text'] # Untyped characters 360 | 361 | char_surface = font.render(char, True, color) 362 | 363 | # Handle line wrapping 364 | if x + char_surface.get_width() > max_width: 365 | x = 70 366 | y += 35 367 | 368 | self.screen.blit(char_surface, (x, y)) 369 | x += char_surface.get_width() 370 | 371 | def handle_typing(self, event): 372 | """Handle typing input with improved feedback""" 373 | if not self.active or self.end: 374 | return 375 | 376 | if event.key == pygame.K_RETURN: 377 | if len(self.input_text) >= len(self.target_text) * 0.8: # Allow completion at 80% 378 | self.calculate_results() 379 | 380 | elif event.key == pygame.K_BACKSPACE: 381 | if len(self.input_text) > 0: 382 | self.input_text = self.input_text[:-1] 383 | self.char_index = len(self.input_text) 384 | # Recalculate correct chars 385 | self.correct_chars = sum(1 for i, c in enumerate(self.input_text) 386 | if i < len(self.target_text) and c == self.target_text[i]) 387 | 388 | elif event.unicode and event.unicode.isprintable(): 389 | self.input_text += event.unicode 390 | 391 | # Check if character is correct 392 | if len(self.input_text) <= len(self.target_text): 393 | if self.input_text[-1] == self.target_text[len(self.input_text) - 1]: 394 | self.correct_chars += 1 395 | else: 396 | self.current_errors += 1 397 | 398 | # Auto-complete when reaching end 399 | if len(self.input_text) >= len(self.target_text): 400 | self.calculate_results() 401 | 402 | def run(self): 403 | """Main game loop with improved structure""" 404 | self.reset_game() 405 | clock = pygame.time.Clock() 406 | 407 | self.running = True 408 | while self.running: 409 | mouse_pos = pygame.mouse.get_pos() 410 | 411 | for event in pygame.event.get(): 412 | if event.type == QUIT: 413 | self.running = False 414 | sys.exit() 415 | 416 | elif event.type == pygame.MOUSEBUTTONDOWN: 417 | if not self.end: 418 | # Check if clicking in input area 419 | input_rect = pygame.Rect(50, 400, self.w - 100, 60) 420 | if input_rect.collidepoint(mouse_pos): 421 | self.active = True 422 | if not self.time_start: 423 | self.time_start = time.time() 424 | else: 425 | # Handle button clicks on results screen 426 | play_again_rect = pygame.Rect(self.w // 2 - 100, self.h - 100, 200, 50) 427 | settings_rect = pygame.Rect(self.w // 2 + 120, self.h - 100, 120, 50) 428 | 429 | if play_again_rect.collidepoint(mouse_pos): 430 | self.reset_game() 431 | elif settings_rect.collidepoint(mouse_pos): 432 | self.show_settings_menu() 433 | 434 | elif event.type == pygame.KEYDOWN: 435 | if event.key == pygame.K_ESCAPE: 436 | if self.active: 437 | self.active = False 438 | else: 439 | self.running = False 440 | elif event.key == pygame.K_F1: # F1 for quick settings 441 | self.show_settings_menu() 442 | elif event.key == pygame.K_F2: # F2 to toggle theme 443 | themes = list(Theme) 444 | current_index = themes.index(self.theme) 445 | self.theme = themes[(current_index + 1) % len(themes)] 446 | self.set_theme_colors() 447 | elif event.key == pygame.K_F3: # F3 reserved for future features 448 | pass # Could add more features here 449 | else: 450 | self.handle_typing(event) 451 | 452 | # Draw everything 453 | if not self.end: 454 | self.draw_game_screen() 455 | else: 456 | self.draw_results_screen() 457 | 458 | pygame.display.flip() 459 | clock.tick(60) 460 | 461 | def draw_game_screen(self): 462 | """Draw the main game screen""" 463 | self.screen.fill(self.colors['bg']) 464 | 465 | # Draw background if available 466 | if self.bg: 467 | # Scale and center background 468 | bg_scaled = pygame.transform.scale(self.bg, (self.w, self.h)) 469 | bg_surface = pygame.Surface((self.w, self.h)) 470 | bg_surface.blit(bg_scaled, (0, 0)) 471 | bg_surface.set_alpha(30) # Make it subtle 472 | self.screen.blit(bg_surface, (0, 0)) 473 | 474 | # Title 475 | self.draw_text("Advanced Speed Typing Test", (self.w // 2, 50), 'large', self.colors['text']) 476 | 477 | # Difficulty indicator 478 | diff_text = f"Difficulty: {self.difficulty.value.title()}" 479 | self.draw_text(diff_text, (self.w // 2, 100), 'small', self.colors['text']) 480 | 481 | # Instructions 482 | if not self.active: 483 | self.draw_text("Click in the text box below and start typing!", 484 | (self.w // 2, 150), 'small', self.colors['text']) 485 | self.draw_text("Press ESC to quit | Press ENTER to finish early (80% minimum)", 486 | (self.w // 2, 180), 'tiny', self.colors['text']) 487 | self.draw_text(f"Theme: {self.theme.value.title()} | Press F2 to change theme", 488 | (self.w // 2, 200), 'tiny', self.colors['text']) 489 | 490 | # Target text label 491 | self.draw_text("Type this text:", (self.w // 2, 250), 'small', self.colors['text']) 492 | 493 | # Main typing area 494 | self.draw_typing_area() 495 | 496 | def show_settings_menu(self): 497 | """Cycle through settings""" 498 | # Cycle through themes 499 | themes = list(Theme) 500 | current_index = themes.index(self.theme) 501 | self.theme = themes[(current_index + 1) % len(themes)] 502 | self.set_theme_colors() 503 | 504 | # Also cycle difficulty 505 | difficulties = list(Difficulty) 506 | current_index = difficulties.index(self.difficulty) 507 | self.difficulty = difficulties[(current_index + 1) % len(difficulties)] 508 | 509 | def reset_game(self): 510 | """Reset game state for a new round""" 511 | # Show splash screen briefly if available 512 | if self.open_img: 513 | self.screen.blit(pygame.transform.scale(self.open_img, (self.w, self.h)), (0, 0)) 514 | pygame.display.flip() 515 | pygame.time.wait(500) # Brief pause 516 | 517 | # Reset game state 518 | self.reset = False 519 | self.end = False 520 | self.active = False 521 | self.input_text = '' 522 | self.time_start = 0 523 | self.total_time = 0 524 | self.wpm = 0 525 | self.accuracy = 0 526 | self.char_index = 0 527 | self.current_errors = 0 528 | self.correct_chars = 0 529 | self.char_colors = [] 530 | 531 | # Get new text based on difficulty 532 | self.target_text = self.get_text_by_difficulty() 533 | if not self.target_text: 534 | self.target_text = "The quick brown fox jumps over the lazy dog." 535 | 536 | # Initialize character colors 537 | self.char_colors = [self.colors['text']] * len(self.target_text) 538 | 539 | 540 | 541 | if __name__ == "__main__": 542 | game = TypingGame() 543 | try: 544 | game.run() 545 | except KeyboardInterrupt: 546 | print("\nGame interrupted by user") 547 | finally: 548 | pygame.quit() 549 | 550 | --------------------------------------------------------------------------------