diff --git a/Webghena b/Webghena new file mode 100644 index 0000000000..6d705601db --- /dev/null +++ b/Webghena @@ -0,0 +1,854 @@ +‏core/index.ts + +‏core/intelligence.ts + +‏core/security.ts + +‏core/utils.ts + +‏/package-lock.json + +‏/package.json + +‏quick-multi-play-intnetspace + +‏export class CoreIntelligence { +‏ private aiName: string; +‏ private capabilities: string[]; +‏ private processingQueue: any[]; +‏ private isInitialized: boolean; + +‏ constructor() { +‏ this.aiName = 'مار'; +‏ this.capabilities = [ + 'تحليل البيانات', + 'اتخاذ القرارات', + 'إدارة الموارد', + 'التحسين التلقائي', + 'التعلم الآلي' + ]; +‏ this.processingQueue = []; +‏ this.isInitialized = false; + } + +‏ public initialize(): void { +‏ console.log(`🤖 [${this.aiName}] بدء تهيئة الذكاء الاصطناعي...`); + +‏ // Simulate AI initialization +‏ setTimeout(() => { +‏ this.isInitialized = true; +‏ console.log(`✅ [${this.aiName}] الذكاء الاصطناعي جاهز للعمل`); +‏ console.log(`📋 القدرات المتاحة: ${this.capabilities.join(', ')}`); + }, 2000); + } + +‏ public async processRequest(requestData: any): Promise { +‏ if (!this.isInitialized) { +‏ throw new Error('الذكاء الاصطناعي غير مهيأ بعد'); + } + +‏ const requestId = this.generateRequestId(); +‏ console.log(`🔄 [${this.aiName}] معالجة طلب: ${requestId}`); + +‏ // Add to processing queue +‏ this.processingQueue.push({ +‏ id: requestId, +‏ data: requestData, +‏ timestamp: new Date().toISOString(), +‏ status: 'processing' + }); + +‏ // Simulate AI processing +‏ await this.simulateProcessing(); + +‏ const result = { +‏ requestId, +‏ aiName: this.aiName, +‏ processedAt: new Date().toISOString(), +‏ result: this.analyzeRequest(requestData), +‏ recommendations: this.generateRecommendations(requestData), +‏ confidence: this.calculateConfidence(requestData) + }; + +‏ // Update queue status +‏ const queueItem = this.processingQueue.find(item => item.id === requestId); +‏ if (queueItem) { +‏ queueItem.status = 'completed'; +‏ queueItem.result = result; + } + +‏ console.log(`✅ [${this.aiName}] اكتمل معالجة الطلب: ${requestId}`); +‏ return result; + } + +‏ private analyzeRequest(data: any): any { +‏ const analysis = { +‏ type: this.detectRequestType(data), +‏ complexity: this.assessComplexity(data), +‏ priority: this.determinePriority(data), +‏ estimatedTime: this.estimateProcessingTime(data) + }; + +‏ return { +‏ analysis, +‏ insights: this.generateInsights(data), +‏ patterns: this.detectPatterns(data) + }; + } + +‏ private detectRequestType(data: any): string { +‏ if (data.action) { +‏ switch (data.action) { +‏ case 'create': return 'إنشاء'; +‏ case 'update': return 'تحديث'; +‏ case 'delete': return 'حذف'; +‏ case 'analyze': return 'تحليل'; +‏ default: return 'غير محدد'; + } + } +‏ return 'طلب عام'; + } + +‏ private assessComplexity(data: any): 'منخفض' | 'متوسط' | 'عالي' { +‏ const dataSize = JSON.stringify(data).length; + +‏ if (dataSize < 1000) return 'منخفض'; +‏ if (dataSize < 5000) return 'متوسط'; +‏ return 'عالي'; + } + +‏ private determinePriority(data: any): 'منخفض' | 'متوسط' | 'عالي' | 'حرج' { +‏ if (data.urgent === true) return 'حرج'; +‏ if (data.priority === 'high') return 'عالي'; +‏ if (data.priority === 'medium') return 'متوسط'; +‏ return 'منخفض'; + } + +‏ private estimateProcessingTime(data: any): string { +‏ const complexity = this.assessComplexity(data); + +‏ switch (complexity) { +‏ case 'منخفض': return '< 1 ثانية'; +‏ case 'متوسط': return '1-5 ثواني'; +‏ case 'عالي': return '5-30 ثانية'; +‏ default: return 'غير محدد'; + } + } + +‏ private generateInsights(data: any): string[] { +‏ const insights: string[] = []; + +‏ if (data.timestamp) { +‏ const requestTime = new Date(data.timestamp); +‏ const now = new Date(); +‏ const delay = now.getTime() - requestTime.getTime(); + +‏ if (delay > 5000) { +‏ insights.push('الطلب قديم نسبياً، قد يحتاج مراجعة'); + } + } + +‏ if (data.user) { +‏ insights.push(`طلب من المستخدم: ${data.user}`); + } + +‏ if (Object.keys(data).length > 10) { +‏ insights.push('طلب معقد يحتوي على بيانات كثيرة'); + } + +‏ return insights; + } + +‏ private detectPatterns(data: any): string[] { +‏ const patterns: string[] = []; + +‏ // Pattern detection logic +‏ if (data.action && data.target) { +‏ patterns.push(`نمط العمل: ${data.action} على ${data.target}`); + } + +‏ if (data.repeated === true) { +‏ patterns.push('طلب متكرر'); + } + +‏ return patterns; + } + +‏ private generateRecommendations(data: any): string[] { +‏ const recommendations: string[] = []; + +‏ const complexity = this.assessComplexity(data); +‏ if (complexity === 'عالي') { +‏ recommendations.push('يُنصح بتقسيم الطلب إلى أجزاء أصغر'); + } + +‏ if (!data.validation) { +‏ recommendations.push('إضافة آلية التحقق للبيانات'); + } + +‏ if (!data.backup) { +‏ recommendations.push('إنشاء نسخة احتياطية قبل التنفيذ'); + } + +‏ return recommendations; + } + +‏ private calculateConfidence(data: any): number { +‏ let confidence = 0.5; // Base confidence + +‏ // Increase confidence based on data completeness +‏ if (data.action) confidence += 0.1; +‏ if (data.target) confidence += 0.1; +‏ if (data.user) confidence += 0.1; +‏ if (data.timestamp) confidence += 0.1; + +‏ // Adjust based on data quality +‏ const hasValidStructure = typeof data === 'object' && data !== null; +‏ if (hasValidStructure) confidence += 0.1; + +‏ return Math.min(confidence, 1.0); + } + +‏ private async simulateProcessing(): Promise { +‏ // Simulate processing time +‏ const processingTime = Math.random() * 1000 + 500; // 0.5-1.5 seconds +‏ return new Promise(resolve => setTimeout(resolve, processingTime)); + } + +‏ private generateRequestId(): string { +‏ const timestamp = Date.now().toString(36); +‏ const random = Math.random().toString(36).substring(2); +‏ return `${timestamp}-${random}`; + } + +‏ public getStatus(): any { +‏ return { +‏ aiName: this.aiName, +‏ initialized: this.isInitialized, +‏ capabilities: this.capabilities, +‏ queueSize: this.processingQueue.length, +‏ activeRequests: this.processingQueue.filter(item => item.status === 'processing').length + }; + } + +‏ public getQueue(): any[] { +‏ return this.processingQueue.map(item => ({ +‏ id: item.id, +‏ timestamp: item.timestamp, +‏ status: item.status + })); + } +} + + +‏server/index.ts + + +‏import React, { useRef, useEffect, useCallback } from 'react'; +‏import { useGameStore } from '@/lib/stores/useGameStore'; +‏import { useChallengeStore } from '@/lib/stores/useChallengeStore'; +‏import { GAME_CONFIG } from '@shared/gameTypes'; +‏import { clampPosition, checkCollision, getDistance } from '@/lib/gameLogic'; + +‏interface ChallengeGameCanvasProps { +‏ width: number; +‏ height: number; +} + +‏export default function ChallengeGameCanvas({ width, height }: ChallengeGameCanvasProps) { +‏ const canvasRef = useRef(null); +‏ const animationFrameRef = useRef(); +‏ const { players, dots, playerId, movePlayer } = useGameStore(); +‏ const { +‏ currentChallenge, +‏ isInChallenge, +‏ challengeStartTime, +‏ challengeScore, +‏ challengeData, +‏ updateChallengeScore, +‏ updateChallengeData, +‏ endChallenge +‏ } = useChallengeStore(); + +‏ // Handle mouse/touch input +‏ const handlePointerMove = useCallback((e: React.PointerEvent) => { +‏ if (!canvasRef.current || !isInChallenge) return; + +‏ const rect = canvasRef.current.getBoundingClientRect(); +‏ const scaleX = GAME_CONFIG.CANVAS_WIDTH / rect.width; +‏ const scaleY = GAME_CONFIG.CANVAS_HEIGHT / rect.height; + +‏ const x = (e.clientX - rect.left) * scaleX; +‏ const y = (e.clientY - rect.top) * scaleY; + +‏ const clamped = clampPosition(x, y, GAME_CONFIG.CANVAS_WIDTH, GAME_CONFIG.CANVAS_HEIGHT); + +‏ // Apply challenge-specific movement restrictions +‏ if (currentChallenge?.type === 'survival') { +‏ const centerX = GAME_CONFIG.CANVAS_WIDTH / 2; +‏ const centerY = GAME_CONFIG.CANVAS_HEIGHT / 2; +‏ const currentRadius = calculateSurvivalRadius(); +‏ const distanceFromCenter = getDistance(clamped.x, clamped.y, centerX, centerY); + +‏ if (distanceFromCenter > currentRadius) { +‏ // Clamp to survival area boundary +‏ const angle = Math.atan2(clamped.y - centerY, clamped.x - centerX); +‏ clamped.x = centerX + Math.cos(angle) * currentRadius; +‏ clamped.y = centerY + Math.sin(angle) * currentRadius; + } + } + +‏ movePlayer(clamped.x, clamped.y); +‏ }, [movePlayer, isInChallenge, currentChallenge]); + +‏ const calculateSurvivalRadius = useCallback(() => { +‏ if (!currentChallenge || !challengeStartTime || currentChallenge.type !== 'survival') { +‏ return GAME_CONFIG.CANVAS_WIDTH / 2; + } + +‏ const elapsed = (Date.now() - challengeStartTime) / 1000; +‏ const config = currentChallenge.config; +‏ const startRadius = config.startRadius || 250; +‏ const shrinkRate = config.shrinkRate || 15; + +‏ return Math.max(50, startRadius - (elapsed * shrinkRate)); +‏ }, [currentChallenge, challengeStartTime]); + +‏ // Check challenge-specific conditions +‏ const checkChallengeConditions = useCallback(() => { +‏ if (!currentChallenge || !isInChallenge || !challengeStartTime) return; + +‏ const currentPlayer = players.get(playerId || ''); +‏ if (!currentPlayer) return; + +‏ const elapsed = (Date.now() - challengeStartTime) / 1000; + +‏ switch (currentChallenge.type) { +‏ case 'speedRun': { +‏ const dotsCollected = challengeData.dotsCollected || 0; +‏ const target = currentChallenge.config.dotsToCollect || 20; + +‏ if (dotsCollected >= target) { +‏ updateChallengeScore(Math.floor((target * 1000) / elapsed)); +‏ endChallenge(true); +‏ } else if (elapsed >= (currentChallenge.config.timeLimit || 60)) { +‏ endChallenge(false); + } +‏ break; + } + +‏ case 'colorMatch': { +‏ const misses = challengeData.misses || 0; +‏ const maxMisses = currentChallenge.config.maxMisses || 3; + +‏ if (misses >= maxMisses) { +‏ endChallenge(false); +‏ } else if (challengeScore >= (currentChallenge.config.targetScore || 15)) { +‏ endChallenge(true); + } +‏ break; + } + +‏ case 'avoidance': { +‏ const misses = challengeData.misses || 0; +‏ const maxMisses = currentChallenge.config.maxMisses || 1; + +‏ if (misses >= maxMisses) { +‏ endChallenge(false); +‏ } else if (challengeScore >= (currentChallenge.config.targetScore || 25)) { +‏ endChallenge(true); + } +‏ break; + } + +‏ case 'kingOfHill': { +‏ const config = currentChallenge.config; +‏ const hillCenter = config.hillCenter || { x: 400, y: 300 }; +‏ const hillRadius = config.hillRadius || 80; +‏ const pointsPerSecond = config.pointsPerSecond || 2; + +‏ const inHill = getDistance(currentPlayer.x, currentPlayer.y, hillCenter.x, hillCenter.y) <= hillRadius; + +‏ if (inHill) { +‏ const timeInHill = (challengeData.timeInHill || 0) + 0.016; // ~60fps +‏ updateChallengeData({ timeInHill }); +‏ updateChallengeScore(Math.floor(timeInHill * pointsPerSecond)); + } + +‏ if (challengeScore >= (config.targetScore || 100)) { +‏ endChallenge(true); +‏ } else if (elapsed >= (config.timeLimit || 90)) { +‏ endChallenge(challengeScore >= (config.targetScore || 100)); + } +‏ break; + } + +‏ case 'survival': { +‏ const centerX = GAME_CONFIG.CANVAS_WIDTH / 2; +‏ const centerY = GAME_CONFIG.CANVAS_HEIGHT / 2; +‏ const currentRadius = calculateSurvivalRadius(); +‏ const distanceFromCenter = getDistance(currentPlayer.x, currentPlayer.y, centerX, centerY); + +‏ if (distanceFromCenter > currentRadius) { +‏ endChallenge(false); +‏ } else { +‏ updateChallengeScore(Math.floor(elapsed * 10)); + +‏ if (elapsed >= (currentChallenge.config.timeLimit || 120)) { +‏ endChallenge(true); + } + } +‏ break; + } + +‏ case 'relay': { +‏ const checkpoints = currentChallenge.config.checkpoints || []; +‏ const currentCheckpoint = challengeData.currentCheckpoint || 0; + +‏ if (currentCheckpoint < checkpoints.length) { +‏ const checkpoint = checkpoints[currentCheckpoint]; +‏ const distance = getDistance(currentPlayer.x, currentPlayer.y, checkpoint.x, checkpoint.y); + +‏ if (distance <= 25) { +‏ const newCheckpoint = currentCheckpoint + 1; +‏ updateChallengeData({ currentCheckpoint: newCheckpoint }); + +‏ if (newCheckpoint >= checkpoints.length) { +‏ updateChallengeScore(Math.floor((checkpoints.length * 1000) / elapsed)); +‏ endChallenge(true); + } + } + } + +‏ if (elapsed >= (currentChallenge.config.timeLimit || 90)) { +‏ endChallenge(false); + } +‏ break; + } + +‏ case 'precision': { +‏ // Precision targets are handled via click events +‏ if (elapsed >= (currentChallenge.duration || 120)) { +‏ const targets = currentChallenge.config.targets || []; +‏ const hits = challengeData.hits || 0; +‏ endChallenge(hits >= targets.length); + } +‏ break; + } + } +‏ }, [currentChallenge, isInChallenge, challengeStartTime, challengeData, challengeScore, players, playerId, updateChallengeScore, updateChallengeData, endChallenge, calculateSurvivalRadius]); + +‏ // Handle dot collection for challenges +‏ const handleDotCollection = useCallback((dot: any, player: any) => { +‏ if (!currentChallenge || !isInChallenge) return false; + +‏ let shouldCollect = true; +‏ let points = dot.points; + +‏ switch (currentChallenge.type) { +‏ case 'speedRun': { +‏ const dotsCollected = (challengeData.dotsCollected || 0) + 1; +‏ updateChallengeData({ dotsCollected }); +‏ break; + } + +‏ case 'colorMatch': { +‏ const allowedColors = currentChallenge.config.allowedColors || []; +‏ const forbiddenColors = currentChallenge.config.forbiddenColors || []; + +‏ if (forbiddenColors.includes(dot.color) || (allowedColors.length > 0 && !allowedColors.includes(dot.color))) { +‏ const misses = (challengeData.misses || 0) + 1; +‏ updateChallengeData({ misses }); +‏ shouldCollect = false; +‏ points = 0; + } +‏ break; + } + +‏ case 'avoidance': { +‏ const forbiddenColors = currentChallenge.config.forbiddenColors || ['#ff4444']; + +‏ if (forbiddenColors.includes(dot.color)) { +‏ const misses = (challengeData.misses || 0) + 1; +‏ updateChallengeData({ misses }); +‏ shouldCollect = false; +‏ points = 0; + } +‏ break; + } + +‏ case 'treasure': { +‏ if (dot.color === '#FFD700') { // Golden dot +‏ points = currentChallenge.config.treasurePoints || 10; + } +‏ break; + } + } + +‏ if (shouldCollect && points > 0) { +‏ updateChallengeScore(challengeScore + points); + } + +‏ return shouldCollect; +‏ }, [currentChallenge, isInChallenge, challengeData, challengeScore, updateChallengeData, updateChallengeScore]); + +‏ // Custom rendering for challenge modes +‏ const renderChallengeElements = useCallback((ctx: CanvasRenderingContext2D) => { +‏ if (!currentChallenge || !isInChallenge) return; + +‏ switch (currentChallenge.type) { +‏ case 'kingOfHill': { +‏ const config = currentChallenge.config; +‏ const hillCenter = config.hillCenter || { x: 400, y: 300 }; +‏ const hillRadius = config.hillRadius || 80; + +‏ // Draw hill area +‏ ctx.fillStyle = 'rgba(255, 215, 0, 0.2)'; +‏ ctx.beginPath(); +‏ ctx.arc(hillCenter.x, hillCenter.y, hillRadius, 0, Math.PI * 2); +‏ ctx.fill(); + +‏ ctx.strokeStyle = '#FFD700'; +‏ ctx.lineWidth = 3; +‏ ctx.stroke(); + +‏ // Draw "KING OF HILL" text +‏ ctx.fillStyle = '#B8860B'; +‏ ctx.font = 'bold 16px Arial'; +‏ ctx.textAlign = 'center'; +‏ ctx.fillText('KING OF HILL', hillCenter.x, hillCenter.y); +‏ break; + } + +‏ case 'survival': { +‏ const centerX = GAME_CONFIG.CANVAS_WIDTH / 2; +‏ const centerY = GAME_CONFIG.CANVAS_HEIGHT / 2; +‏ const currentRadius = calculateSurvivalRadius(); + +‏ // Draw safe area +‏ ctx.fillStyle = 'rgba(0, 255, 0, 0.1)'; +‏ ctx.beginPath(); +‏ ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2); +‏ ctx.fill(); + +‏ // Draw danger zone +‏ ctx.fillStyle = 'rgba(255, 0, 0, 0.3)'; +‏ ctx.fillRect(0, 0, GAME_CONFIG.CANVAS_WIDTH, GAME_CONFIG.CANVAS_HEIGHT); + +‏ // Cut out safe area +‏ ctx.globalCompositeOperation = 'destination-out'; +‏ ctx.beginPath(); +‏ ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2); +‏ ctx.fill(); +‏ ctx.globalCompositeOperation = 'source-over'; + +‏ // Draw border +‏ ctx.strokeStyle = '#ff4444'; +‏ ctx.lineWidth = 4; +‏ ctx.beginPath(); +‏ ctx.arc(centerX, centerY, currentRadius, 0, Math.PI * 2); +‏ ctx.stroke(); +‏ break; + } + +‏ case 'relay': { +‏ const checkpoints = currentChallenge.config.checkpoints || []; +‏ const currentCheckpoint = challengeData.currentCheckpoint || 0; + +‏ checkpoints.forEach((checkpoint, index) => { +‏ const isActive = index === currentCheckpoint; +‏ const isCompleted = index < currentCheckpoint; + +‏ ctx.fillStyle = isCompleted ? '#22c55e' : isActive ? '#3b82f6' : '#94a3b8'; +‏ ctx.beginPath(); +‏ ctx.arc(checkpoint.x, checkpoint.y, 20, 0, Math.PI * 2); +‏ ctx.fill(); + +‏ ctx.fillStyle = 'white'; +‏ ctx.font = 'bold 14px Arial'; +‏ ctx.textAlign = 'center'; +‏ ctx.fillText((index + 1).toString(), checkpoint.x, checkpoint.y + 5); + }); +‏ break; + } + +‏ case 'precision': { +‏ const targets = currentChallenge.config.targets || []; +‏ const hits = challengeData.hits || 0; + +‏ targets.forEach((target, index) => { +‏ const isHit = index < hits; + +‏ ctx.strokeStyle = isHit ? '#22c55e' : '#ef4444'; +‏ ctx.lineWidth = 3; +‏ ctx.beginPath(); +‏ ctx.arc(target.x, target.y, target.radius, 0, Math.PI * 2); +‏ ctx.stroke(); + +‏ if (!isHit) { +‏ ctx.strokeStyle = '#ef4444'; +‏ ctx.lineWidth = 2; +‏ ctx.beginPath(); +‏ ctx.moveTo(target.x - 10, target.y - 10); +‏ ctx.lineTo(target.x + 10, target.y + 10); +‏ ctx.moveTo(target.x + 10, target.y - 10); +‏ ctx.lineTo(target.x - 10, target.y + 10); +‏ ctx.stroke(); +‏ } else { +‏ ctx.fillStyle = '#22c55e'; +‏ ctx.font = 'bold 16px Arial'; +‏ ctx.textAlign = 'center'; +‏ ctx.fillText('✓', target.x, target.y + 6); + } + }); +‏ break; + } + } +‏ }, [currentChallenge, isInChallenge, challengeData, calculateSurvivalRadius]); + +‏ // Handle precision target clicks +‏ const handleCanvasClick = useCallback((e: React.MouseEvent) => { +‏ if (!currentChallenge || currentChallenge.type !== 'precision' || !isInChallenge) return; + +‏ const rect = canvasRef.current?.getBoundingClientRect(); +‏ if (!rect) return; + +‏ const scaleX = GAME_CONFIG.CANVAS_WIDTH / rect.width; +‏ const scaleY = GAME_CONFIG.CANVAS_HEIGHT / rect.height; + +‏ const x = (e.clientX - rect.left) * scaleX; +‏ const y = (e.clientY - rect.top) * scaleY; + +‏ const targets = currentChallenge.config.targets || []; +‏ const hits = challengeData.hits || 0; + +‏ if (hits < targets.length) { +‏ const target = targets[hits]; +‏ const distance = getDistance(x, y, target.x, target.y); + +‏ if (distance <= target.radius) { +‏ const newHits = hits + 1; +‏ updateChallengeData({ hits: newHits }); +‏ updateChallengeScore(challengeScore + 10); + +‏ if (newHits >= targets.length) { +‏ endChallenge(true); + } +‏ } else { +‏ const misses = (challengeData.misses || 0) + 1; +‏ updateChallengeData({ misses }); + +‏ const penalty = currentChallenge.config.penaltyPerMiss || 10; +‏ updateChallengeScore(Math.max(0, challengeScore - penalty)); + +‏ if (misses >= (currentChallenge.config.maxMisses || 2)) { +‏ endChallenge(false); + } + } + } +‏ }, [currentChallenge, isInChallenge, challengeData, challengeScore, updateChallengeData, updateChallengeScore, endChallenge]); + +‏ // Main render function +‏ const render = useCallback(() => { +‏ const canvas = canvasRef.current; +‏ if (!canvas) return; + +‏ const ctx = canvas.getContext('2d'); +‏ if (!ctx) return; + +‏ // Clear canvas +‏ ctx.fillStyle = '#f0f0f0'; +‏ ctx.fillRect(0, 0, GAME_CONFIG.CANVAS_WIDTH, GAME_CONFIG.CANVAS_HEIGHT); + +‏ // Draw grid pattern +‏ ctx.strokeStyle = '#e0e0e0'; +‏ ctx.lineWidth = 1; +‏ const gridSize = 50; +‏ for (let x = 0; x <= GAME_CONFIG.CANVAS_WIDTH; x += gridSize) { +‏ ctx.beginPath(); +‏ ctx.moveTo(x, 0); +‏ ctx.lineTo(x, GAME_CONFIG.CANVAS_HEIGHT); +‏ ctx.stroke(); + } +‏ for (let y = 0; y <= GAME_CONFIG.CANVAS_HEIGHT; y += gridSize) { +‏ ctx.beginPath(); +‏ ctx.moveTo(0, y); +‏ ctx.lineTo(GAME_CONFIG.CANVAS_WIDTH, y); +‏ ctx.stroke(); + } + +‏ // Render challenge-specific elements +‏ renderChallengeElements(ctx); + +‏ // Draw dots (with challenge-specific modifications) +‏ dots.forEach(dot => { +‏ let dotColor = dot.color; + +‏ // Special rendering for treasure hunt +‏ if (currentChallenge?.type === 'treasure' && dot.color === '#FFD700') { +‏ // Make treasure dots sparkle +‏ const time = Date.now() / 1000; +‏ const sparkle = Math.sin(time * 4) * 0.3 + 0.7; +‏ ctx.save(); +‏ ctx.globalAlpha = sparkle; + +‏ // Draw larger golden dot +‏ ctx.fillStyle = '#FFD700'; +‏ ctx.beginPath(); +‏ ctx.arc(dot.x, dot.y, GAME_CONFIG.DOT_SIZE * 0.8, 0, Math.PI * 2); +‏ ctx.fill(); + +‏ // Draw sparkle effect +‏ ctx.strokeStyle = '#FFF700'; +‏ ctx.lineWidth = 2; +‏ const sparkleSize = 8; +‏ ctx.beginPath(); +‏ ctx.moveTo(dot.x - sparkleSize, dot.y); +‏ ctx.lineTo(dot.x + sparkleSize, dot.y); +‏ ctx.moveTo(dot.x, dot.y - sparkleSize); +‏ ctx.lineTo(dot.x, dot.y + sparkleSize); +‏ ctx.stroke(); + +‏ ctx.restore(); +‏ } else { +‏ ctx.fillStyle = dotColor; +‏ ctx.beginPath(); +‏ ctx.arc(dot.x, dot.y, GAME_CONFIG.DOT_SIZE / 2, 0, Math.PI * 2); +‏ ctx.fill(); + } + +‏ // Draw points value +‏ ctx.fillStyle = '#333'; +‏ ctx.font = '12px Arial'; +‏ ctx.textAlign = 'center'; +‏ ctx.fillText(dot.points.toString(), dot.x, dot.y - GAME_CONFIG.DOT_SIZE); + }); + +‏ // Draw players +‏ const playersArray = Array.from(players.values()); +‏ playersArray.forEach(player => { +‏ // Player circle +‏ ctx.fillStyle = player.color; +‏ ctx.beginPath(); +‏ ctx.arc(player.x, player.y, GAME_CONFIG.PLAYER_SIZE / 2, 0, Math.PI * 2); +‏ ctx.fill(); + +‏ // Player border +‏ ctx.strokeStyle = player.id === playerId ? '#fff' : '#333'; +‏ ctx.lineWidth = player.id === playerId ? 3 : 2; +‏ ctx.stroke(); + +‏ // Player name +‏ ctx.fillStyle = '#333'; +‏ ctx.font = 'bold 14px Arial'; +‏ ctx.textAlign = 'center'; +‏ ctx.fillText(player.name, player.x, player.y - GAME_CONFIG.PLAYER_SIZE); + }); + +‏ // Check challenge conditions each frame +‏ checkChallengeConditions(); + +‏ animationFrameRef.current = requestAnimationFrame(render); +‏ }, [players, dots, playerId, currentChallenge, isInChallenge, challengeData, renderChallengeElements, checkChallengeConditions]); + +‏ useEffect(() => { +‏ if (isInChallenge) { +‏ render(); + } + +‏ return () => { +‏ if (animationFrameRef.current) { +‏ cancelAnimationFrame(animationFrameRef.current); + } + }; +‏ }, [render, isInChallenge]); + +‏ if (!isInChallenge) { +‏ return null; + } + +‏ return ( +‏ + ); +} + + + +2. شغّل كل خدمة في نافذة منفصلة (يفضل تشغيل النواة أولاً): + +- **النواة المركزية (CoreAI):** + ``` +‏ cd core +‏ npm start + ``` + +- **بوابة النظام (API Gateway):** + ``` +‏ cd api +‏ npm start + ``` + +- **خدمة المنتجات:** + ``` +‏ cd services/products +‏ npm start + ``` + +- **واجهة المستخدم (Next.js):** + ``` +‏ cd frontend/web +‏ npm run dev + ``` + +3. للوصول للمنصة: +- افتح المتصفح على: + ``` +‏ http://localhost:3000/ + ``` +- ستشاهد قائمة المنتجات وعنوان المنصة. + + +‎2. شغّل كل خدمة في نافذة منفصلة (يفضل تشغيل النواة أولاً): + +‎- **النواة المركزية (CoreAI):** + ``` +‎‏ cd core +‎‏ npm start + ``` + +‎- **بوابة النظام (API Gateway):** + ``` +‎‏ cd api +‎‏ npm start + ``` + +‎- **خدمة المنتجات:** + ``` +‎‏ cd services/products +‎‏ npm start + ``` + +‎- **واجهة المستخدم (Next.js):** + ``` +‎‏ cd frontend/web +‎‏ npm run dev + ``` + +‎3. للوصول للمنصة: +‎- افتح المتصفح على: + ``` +‎‏ http://localhost:3000/