import json import os import random import time # ← এই লাইনটি যোগ করতে হবে from dataclasses import dataclass, asdict from typing import List, Dict, Optional, Tuple from enum import Enum import math from datetime import datetime from rng_system import get_rng class AlienType(Enum): """এলিয়েনের ধরণ""" SCOUT = "scout" # ছোট, দ্রুত FIGHTER = "fighter" # মাঝারি, স্ট্যান্ডার্ড BOMBER = "bomber" # বড়, ধীর BOSS = "boss" # খুব বড়, শক্তিশালী class AlienBehavior(Enum): """এলিয়েনের আচরণের ধরণ (ডিটারমিনিস্টিক)""" DIVE = "dive" # ডাইভ অ্যাটাক CIRCLE = "circle" # বৃত্তাকার পথ STRAIGHT = "straight" # সরলরেখা ZIGZAG = "zigzag" # জিগজ্যাগ FOLLOW = "follow" # প্লেয়ার ফলো RANDOM = "random" # এলোমেলো (র‍্যান্ডম) @dataclass class AlienPattern: """এলিয়েন আক্রমণের প্যাটার্ন (ডিটারমিনিস্টিক)""" behavior: AlienBehavior speed: float amplitude: float # জিগজ্যাগ/সার্কেলের জন্য frequency: float # জিগজ্যাগের ফ্রিকোয়েন্সি duration: float # প্যাটার্ন চলার সময় next_pattern: Optional['AlienPattern'] = None @dataclass class Alien: """এলিয়েন অবজেক্ট""" id: int type: AlienType x: float y: float health: int pattern: AlienPattern pattern_start_time: float speed_multiplier: float def to_dict(self): return { 'id': self.id, 'type': self.type.value, 'x': round(self.x, 2), 'y': round(self.y, 2), 'health': self.health, 'pattern': self.pattern.behavior.value } @dataclass class SpawnEvent: """স্পন ইভেন্ট""" time: float alien_type: AlienType x: float y: float pattern: AlienPattern class AlienPatternLibrary: """ এলিয়েন প্যাটার্ন লাইব্রেরি - ডিটারমিনিস্টিক প্যাটার্নের সেট PDF অনুযায়ী: এলিয়েনরা ডিটারমিনিস্টিক, র‍্যান্ডম নয় """ def __init__(self, patterns_file: str = "data/alien_patterns.json"): self.patterns_file = patterns_file self.patterns: Dict[AlienType, List[AlienPattern]] = {} self._load_patterns() def _load_patterns(self): """প্যাটার্ন লোড করা""" if os.path.exists(self.patterns_file): with open(self.patterns_file, 'r') as f: data = json.load(f) for alien_type, patterns in data.items(): self.patterns[AlienType(alien_type)] = [ AlienPattern(**p) for p in patterns ] else: # ডিফল্ট প্যাটার্ন তৈরি self._create_default_patterns() def _create_default_patterns(self): """ডিফল্ট প্যাটার্ন তৈরি (PDF-এর মতো)""" # Scout এলিয়েনের প্যাটার্ন self.patterns[AlienType.SCOUT] = [ AlienPattern(AlienBehavior.DIVE, 5.0, 0, 0, 2.0), AlienPattern(AlienBehavior.STRAIGHT, 4.0, 0, 0, 1.5), AlienPattern(AlienBehavior.CIRCLE, 3.0, 50, 1, 3.0), AlienPattern(AlienBehavior.ZIGZAG, 4.5, 30, 2, 2.5) ] # Fighter এলিয়েনের প্যাটার্ন self.patterns[AlienType.FIGHTER] = [ AlienPattern(AlienBehavior.FOLLOW, 3.5, 0, 0, 3.0), AlienPattern(AlienBehavior.DIVE, 4.0, 0, 0, 2.5), AlienPattern(AlienBehavior.STRAIGHT, 3.0, 0, 0, 2.0), AlienPattern(AlienBehavior.ZIGZAG, 3.5, 40, 1.5, 3.0) ] # Bomber এলিয়েনের প্যাটার্ন self.patterns[AlienType.BOMBER] = [ AlienPattern(AlienBehavior.STRAIGHT, 2.0, 0, 0, 4.0), AlienPattern(AlienBehavior.CIRCLE, 1.8, 80, 0.5, 5.0), AlienPattern(AlienBehavior.FOLLOW, 2.2, 0, 0, 3.5) ] # Boss এলিয়েনের প্যাটার্ন self.patterns[AlienType.BOSS] = [ AlienPattern(AlienBehavior.CIRCLE, 1.5, 100, 0.3, 8.0), AlienPattern(AlienBehavior.FOLLOW, 2.0, 0, 0, 5.0), AlienPattern(AlienBehavior.DIVE, 2.5, 0, 0, 4.0), AlienPattern(AlienBehavior.STRAIGHT, 1.8, 0, 0, 6.0) ] def get_pattern_cycle(self, alien_type: AlienType) -> List[AlienPattern]: """একটি এলিয়েনের জন্য প্যাটার্ন সাইকেল রিটার্ন করে""" return self.patterns.get(alien_type, self.patterns[AlienType.FIGHTER]) class AlienSpawner: """ এলিয়েন স্পনার - PDF-এর SpawnAlien রুটিনের ইমপ্লিমেন্টেশন র‍্যান্ডম অবস্থান তৈরি করতে RNG ব্যবহার করে, কিন্তু এলিয়েনের আচরণ ডিটারমিনিস্টিক """ def __init__(self, pattern_library: AlienPatternLibrary, screen_width: int = 800, screen_height: int = 600): self.rng = get_rng() self.pattern_library = pattern_library self.screen_width = screen_width self.screen_height = screen_height self.aliens: List[Alien] = [] self.spawn_history: List[SpawnEvent] = [] self.next_alien_id = 0 # স্পন প্যারামিটার self.spawn_rate = 0.5 # প্রতি সেকেন্ডে এলিয়েন self.last_spawn_time = time.time() # ← এখানে time.time() ব্যবহার করা হয়েছে self.max_aliens = 20 # স্ট্যাটিস্টিক্স self.total_spawned = 0 self.total_killed = 0 def _get_random_spawn_position(self) -> Tuple[float, float]: """ এলোমেলো স্পন অবস্থান (র‍্যান্ডম - PDF অনুযায়ী) """ side = self.rng.next_random_range(0, 3) # 0=উপরে, 1=নিচে, 2=বামে, 3=ডানে if side == 0: # উপরে x = self.rng.next_random_float(0, self.screen_width) y = -50 elif side == 1: # নিচে x = self.rng.next_random_float(0, self.screen_width) y = self.screen_height + 50 elif side == 2: # বামে x = -50 y = self.rng.next_random_float(0, self.screen_height) else: # ডানে x = self.screen_width + 50 y = self.rng.next_random_float(0, self.screen_height) return x, y def _select_alien_type(self) -> AlienType: """ এলোমেলো এলিয়েন টাইপ সিলেক্ট (র‍্যান্ডম) """ r = self.rng.next_random_float() if r < 0.5: # ৫০% scout return AlienType.SCOUT elif r < 0.8: # ৩০% fighter return AlienType.FIGHTER elif r < 0.95: # ১৫% bomber return AlienType.BOMBER else: # ৫% boss return AlienType.BOSS def _create_alien(self, alien_type: AlienType, x: float, y: float) -> Alien: """ নতুন এলিয়েন তৈরি """ # এলিয়েন টাইপ অনুযায়ী স্বাস্থ্য health_map = { AlienType.SCOUT: 1, AlienType.FIGHTER: 3, AlienType.BOMBER: 5, AlienType.BOSS: 20 } # প্যাটার্ন সাইকেল থেকে প্রথম প্যাটার্ন নেওয়া patterns = self.pattern_library.get_pattern_cycle(alien_type) pattern = patterns[0] # স্পিড মাল্টিপ্লায়ার (ছোট ভ্যারিয়েশন) speed_multiplier = 0.9 + self.rng.next_random_float() * 0.2 alien = Alien( id=self.next_alien_id, type=alien_type, x=x, y=y, health=health_map[alien_type], pattern=pattern, pattern_start_time=time.time(), speed_multiplier=speed_multiplier ) self.next_alien_id += 1 return alien def update(self, dt: float, player_x: float = 400, player_y: float = 300): """ প্রতি ফ্রেমে আপডেট """ current_time = time.time() # নতুন এলিয়েন স্পন if (len(self.aliens) < self.max_aliens and current_time - self.last_spawn_time > 1.0 / self.spawn_rate): alien_type = self._select_alien_type() x, y = self._get_random_spawn_position() alien = self._create_alien(alien_type, x, y) self.aliens.append(alien) self.spawn_history.append(SpawnEvent( time=current_time, alien_type=alien_type, x=x, y=y, pattern=alien.pattern )) self.total_spawned += 1 self.last_spawn_time = current_time # এলিয়েনদের অবস্থান আপডেট (ডিটারমিনিস্টিক প্যাটার্ন অনুযায়ী) aliens_to_remove = [] for alien in self.aliens: self._update_alien_position(alien, dt, player_x, player_y) # স্ক্রিনের বাইরে চলে গেলে রিমুভ if (alien.x < -200 or alien.x > self.screen_width + 200 or alien.y < -200 or alien.y > self.screen_height + 200): aliens_to_remove.append(alien) # মৃত এলিয়েন রিমুভ for alien in aliens_to_remove: if alien in self.aliens: self.aliens.remove(alien) self.total_killed += 1 def _update_alien_position(self, alien: Alien, dt: float, player_x: float, player_y: float): """ এলিয়েনের অবস্থান আপডেট (প্যাটার্ন অনুযায়ী - ডিটারমিনিস্টিক) """ time_in_pattern = time.time() - alien.pattern_start_time # প্যাটার্নের সময় শেষ হলে পরবর্তী প্যাটার্নে যাওয়া if time_in_pattern > alien.pattern.duration: patterns = self.pattern_library.get_pattern_cycle(alien.type) current_index = patterns.index(alien.pattern) if alien.pattern in patterns else 0 next_index = (current_index + 1) % len(patterns) alien.pattern = patterns[next_index] alien.pattern_start_time = time.time() time_in_pattern = 0 speed = alien.pattern.speed * alien.speed_multiplier * dt * 60 # 60 FPS ধরে # প্যাটার্ন অনুযায়ী মুভমেন্ট if alien.pattern.behavior == AlienBehavior.DIVE: # প্লেয়ারের দিকে ডাইভ dx = player_x - alien.x dy = player_y - alien.y dist = math.sqrt(dx*dx + dy*dy) if dist > 0: alien.x += (dx / dist) * speed alien.y += (dy / dist) * speed elif alien.pattern.behavior == AlienBehavior.CIRCLE: # বৃত্তাকার পথ angle = time_in_pattern * alien.pattern.frequency alien.x += math.cos(angle) * speed alien.y += math.sin(angle) * speed elif alien.pattern.behavior == AlienBehavior.STRAIGHT: # সরলরেখায় (পূর্ব নির্ধারিত দিকে) alien.x -= speed # বামে elif alien.pattern.behavior == AlienBehavior.ZIGZAG: # জিগজ্যাগ প্যাটার্ন alien.x -= speed alien.y += math.sin(time_in_pattern * alien.pattern.frequency) * alien.pattern.amplitude * dt elif alien.pattern.behavior == AlienBehavior.FOLLOW: # প্লেয়ারকে ফলো dx = player_x - alien.x dy = player_y - alien.y dist = math.sqrt(dx*dx + dy*dy) if dist > 100: # ১০০ পিক্সেল দূরত্বে রাখে if dist > 0: alien.x += (dx / dist) * speed * 0.5 alien.y += (dy / dist) * speed * 0.5 # র‍্যান্ডম বিহেভিয়ার (শুধু যদি সেট করা থাকে) elif alien.pattern.behavior == AlienBehavior.RANDOM: alien.x += (self.rng.next_random_float() - 0.5) * speed * 2 alien.y += (self.rng.next_random_float() - 0.5) * speed * 2 def damage_alien(self, alien_id: int, damage: int = 1) -> bool: """এলিয়েনকে আঘাত করা""" for alien in self.aliens: if alien.id == alien_id: alien.health -= damage if alien.health <= 0: self.aliens.remove(alien) self.total_killed += 1 return True break return False def get_aliens_data(self) -> List[dict]: """UI-এর জন্য এলিয়েন ডাটা""" return [alien.to_dict() for alien in self.aliens] def get_stats(self) -> dict: """পরিসংখ্যান""" return { 'total_spawned': self.total_spawned, 'total_killed': self.total_killed, 'active_aliens': len(self.aliens), 'spawn_rate': self.spawn_rate } def get_spawn_history(self, limit: int = 50) -> List[dict]: """স্পন হিস্ট্রি""" return [ { 'time': datetime.fromtimestamp(e.time).strftime('%H:%M:%S'), 'type': e.alien_type.value, 'position': f"({int(e.x)},{int(e.y)})" } for e in self.spawn_history[-limit:] ] class AlienAIManager: """ এলিয়েন এআই ম্যানেজার - ডিটারমিনিস্টিক প্যাটার্ন ম্যানেজ করে PDF অনুযায়ী: এলিয়েনরা ডিটারমিনিস্টিক """ def __init__(self): self.pattern_library = AlienPatternLibrary() self.current_cycle_index = 0 self.cycle_length = 4 # প্রতি ৪ রাউন্ডে প্যাটার্ন রিসেট def get_attack_wave_pattern(self, wave_number: int) -> List[AlienPattern]: """ ওয়েব নম্বর অনুযায়ী অ্যাটাক প্যাটার্ন ডিটারমিনিস্টিক - প্রতি ওয়েভে একই প্যাটার্ন রিপিট """ base_pattern = self.pattern_library.get_pattern_cycle(AlienType.FIGHTER) # ওয়েব নম্বর অনুযায়ী প্যাটার্ন মডিফাই wave_index = (wave_number // self.cycle_length) % len(base_pattern) return [base_pattern[wave_index]] def predict_next_attack(self, current_wave: int) -> str: """ পরবর্তী অ্যাটাকের ধরণ প্রেডিক্ট (ডিটারমিনিস্টিক) """ next_pattern = self.get_attack_wave_pattern(current_wave + 1) return f"পরবর্তী অ্যাটাক: {next_pattern[0].behavior.value}"