// Données basées sur les sources GitHub Jeff Sackmann et API tennis const playersData = { "alcaraz": { id: "alcaraz", name: "Carlos Alcaraz", nationality: "Espagne", age: 23, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/alcaraz_head_24.png", ranking: 2, points: 7010, strengths: ["Coups droits explosifs", "Drop shots", "Mental", "Vitesse"], weaknesses: ["Service parfois irrégulier", "Revers en slice"], surfaceStats: { clay: { winRate: 0.82, titles: 5 }, hard: { winRate: 0.78, titles: 3 }, grass: { winRate: 0.71, titles: 1 } }, recentForm: ["W", "W", "L", "W", "W"] }, "sinner": { id: "sinner", name: "Jannik Sinner", nationality: "Italie", age: 24, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/sinner_head_24.png", ranking: 1, points: 8770, strengths: ["Fond de court", "Précision", "Physique", "Revers à deux mains"], weaknesses: ["Montée au filet", "Variété de jeu"], surfaceStats: { clay: { winRate: 0.79, titles: 2 }, hard: { winRate: 0.85, titles: 6 }, grass: { winRate: 0.68, titles: 0 } }, recentForm: ["W", "W", "W", "L", "W"] }, "nadal": { id: "nadal", name: "Rafael Nadal", nationality: "Espagne", age: 40, handedness: "Gaucher", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/nadal_head_24.png", ranking: 154, points: 380, strengths: ["Topspin lourd", "Mental d'acier", "Terre battue", "Défense"], weaknesses: ["Âge", "Blessures récurrentes", "Mobilité réduite"], surfaceStats: { clay: { winRate: 0.95, titles: 14 }, hard: { winRate: 0.72, titles: 4 }, grass: { winRate: 0.65, titles: 0 } }, recentForm: ["L", "W", "L", "L", "W"] }, "djokovic": { id: "djokovic", name: "Novak Djokovic", nationality: "Serbie", age: 39, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/djokovic_head_24.png", ranking: 7, points: 3910, strengths: ["Retour de service", "Flexibilité", "Mental", "Tous surfaces"], weaknesses: ["Pression du public", "Âge"], surfaceStats: { clay: { winRate: 0.80, titles: 2 }, hard: { winRate: 0.84, titles: 10 }, grass: { winRate: 0.86, titles: 7 } }, recentForm: ["W", "L", "W", "W", "L"] }, "medvedev": { id: "medvedev", name: "Daniil Medvedev", nationality: "Russie", age: 30, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/medvedev_head_24.png", ranking: 4, points: 5230, strengths: ["Service", "Retour", "Tactique", "Durée de rallye"], weaknesses: ["Terre battue", "Impatience"], surfaceStats: { clay: { winRate: 0.65, titles: 0 }, hard: { winRate: 0.82, titles: 6 }, grass: { winRate: 0.62, titles: 0 } }, recentForm: ["L", "W", "W", "L", "W"] }, "zverev": { id: "zverev", name: "Alexander Zverev", nationality: "Allemagne", age: 29, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/zverev_head_24.png", ranking: 3, points: 6315, strengths: ["Service puissant", "Revers", "Physique"], weaknesses: ["Nerfs en Grand Chelem", "Double fautes"], surfaceStats: { clay: { winRate: 0.76, titles: 2 }, hard: { winRate: 0.75, titles: 5 }, grass: { winRate: 0.64, titles: 0 } }, recentForm: ["W", "W", "L", "W", "W"] }, "rublev": { id: "rublev", name: "Andrey Rublev", nationality: "Russie", age: 28, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/rublev_head_24.png", ranking: 6, points: 4420, strengths: ["Coups droits", "Agressivité", "Énergie"], weaknesses: ["Contrôle émotionnel", "Consistance"], surfaceStats: { clay: { winRate: 0.74, titles: 1 }, hard: { winRate: 0.76, titles: 4 }, grass: { winRate: 0.58, titles: 0 } }, recentForm: ["L", "L", "W", "W", "L"] }, "ruud": { id: "ruud", name: "Casper Ruud", nationality: "Norvège", age: 27, handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/ruud_head_24.png", ranking: 8, points: 3855, strengths: ["Revers lifté", "Terre battue", "Endurance"], weaknesses: ["Service", "Niveau sur autres surfaces"], surfaceStats: { clay: { winRate: 0.78, titles: 3 }, hard: { winRate: 0.65, titles: 0 }, grass: { winRate: 0.55, titles: 0 } }, recentForm: ["W", "L", "W", "L", "W"] } }; // Matches du tournoi (Tableau principal simulé) const tournamentMatches = [ { id: 1, round: "Finale", player1: "alcaraz", player2: "sinner", date: "2026-06-07", court: "Court Philippe-Chatrier", status: "upcoming" }, { id: 2, round: "Demi-finale", player1: "alcaraz", player2: "zverev", date: "2026-06-05", court: "Court Philippe-Chatrier", status: "completed", winner: "alcaraz", score: "6-3, 6-2, 6-4" }, { id: 3, round: "Demi-finale", player1: "sinner", player2: "nadal", date: "2026-06-05", court: "Court Philippe-Chatrier", status: "completed", winner: "sinner", score: "7-6, 6-4, 3-6, 6-3" }, { id: 4, round: "Quart de finale", player1: "alcaraz", player2: "rublev", date: "2026-06-03", court: "Court Philippe-Chatrier", status: "completed", winner: "alcaraz", score: "6-4, 6-2, 6-3" }, { id: 5, round: "Quart de finale", player1: "zverev", player2: "medvedev", date: "2026-06-03", court: "Court Suzanne-Lenglen", status: "completed", winner: "zverev", score: "7-6, 6-4, 6-7, 6-3" } ]; // Historique des confrontations (H2H) const headToHead = { "alcaraz-sinner": { total: 11, alcaraz: 5, sinner: 6, clay: { alcaraz: 3, sinner: 1 }, lastMeetings: [ { date: "2025-11-15", tournament: "ATP Finals", winner: "sinner", score: "6-3, 6-4" }, { date: "2025-09-10", tournament: "US Open", winner: "alcaraz", score: "6-2, 6-4, 7-6" } ] }, "alcaraz-nadal": { total: 8, alcaraz: 4, nadel: 4, clay: { alcaraz: 2, nadal: 2 }, lastMeetings: [ { date: "2025-05-15", tournament: "Rome Masters", winner: "alcaraz", score: "6-4, 6-3" } ] }, "sinner-nadal": { total: 5, sinner: 3, nadal: 2, clay: { sinner: 1, nadal: 1 }, lastMeetings: [ { date: "2025-06-02", tournament: "Roland Garros", winner: "sinner", score: "6-3, 6-4, 6-2" } ] } }; // Fonction pour calculer les probabilités function calculateWinProbability(player1Id, player2Id, surface = 'clay') { const p1 = playersData[player1Id]; const p2 = playersData[player2Id]; let prob1 = 50; let prob2 = 50; // Facteur ranking const rankingDiff = p2.ranking - p1.ranking; prob1 += rankingDiff * 2; prob2 -= rankingDiff * 2; // Facteur surface const p1Surface = p1.surfaceStats[surface].winRate * 100; const p2Surface = p2.surfaceStats[surface].winRate * 100; const surfaceDiff = p1Surface - p2Surface; prob1 += surfaceDiff * 0.5; prob2 -= surfaceDiff * 0.5; // Facteur forme récente const p1Form = p1.recentForm.filter(r => r === 'W').length / 5; const p2Form = p2.recentForm.filter(r => r === 'W').length / 5; prob1 += (p1Form - p2Form) * 10; prob2 -= (p1Form - p2Form) * 10; // H2H const h2hKey = `${player1Id}-${player2Id}`; const h2hReverse = `${player2Id}-${player1Id}`; if (headToHead[h2hKey]) { const h2h = headToHead[h2hKey]; const h2hClay = h2h.clay ? (h2h.alcaraz || h2h.sinner) : h2h.alcaraz; const totalClay = h2h.clay ? (h2h.clay.alcaraz + h2h.clay.sinner) : h2h.total; if (totalClay > 0) { const h2hAdvantage = (h2hClay / totalClay - 0.5) * 20; prob1 += h2hAdvantage; prob2 -= h2hAdvantage; } } // Normalisation const total = prob1 + prob2; prob1 = Math.round((prob1 / total) * 100); prob2 = 100 - prob1; return { player1: Math.max(10, Math.min(90, prob1)), player2: Math.max(10, Math.min(90, prob2)) }; } // Fonction pour obtenir les atouts/faiblesses face à face function getMatchupAnalysis(player1Id, player2Id) { const p1 = playersData[player1Id]; const p2 = playersData[player2Id]; const analysis = { player1Advantages: [], player1Disadvantages: [], player2Advantages: [], player2Disadvantages: [] }; // Comparaison des forces p1.strengths.forEach(strength => { if (!p2.strengths.includes(strength) && !p2.weaknesses.includes(strength)) { analysis.player1Advantages.push(strength); } }); p2.strengths.forEach(strength => { if (!p1.strengths.includes(strength) && !p1.weaknesses.includes(strength)) { analysis.player2Advantages.push(strength); } }); // Exploitation des faiblesses p1.weaknesses.forEach(weakness => { if (p2.strengths.some(s => s.toLowerCase().includes(weakness.toLowerCase().split(' ')[0]))) { analysis.player2Advantages.push(`Exploite: ${weakness}`); } }); p2.weaknesses.forEach(weakness => { if (p1.strengths.some(s => s.toLowerCase().includes(weakness.toLowerCase().split(' ')[0]))) { analysis.player1Advantages.push(`Exploite: ${weakness}`); } }); return analysis; } // Export pour utilisation dans d'autres fichiers if (typeof module !== 'undefined' && module.exports) { module.exports = { playersData, tournamentMatches, headToHead, calculateWinProbability, getMatchupAnalysis }; }