// Données officielles et simulées pour Roland Garros 2026 const playersData = { // ---- SIMPLE MESSIEURS ---- "alcaraz": { id: "alcaraz", name: "Carlos Alcaraz", gender: "Messieurs", nationality: "Espagne", age: 23, height: "1.83 m", 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 amortis", "Vitesse de déplacement", "Couverture de terrain"], weaknesses: ["Service irrégulier sous pression", "Prise de risque maximale"], surfaceStats: { clay: { winRate: 0.83 }, hard: { winRate: 0.78 }, grass: { winRate: 0.75 } }, recentForm: ["W", "W", "L", "W", "W"] }, "sinner": { id: "sinner", name: "Jannik Sinner", gender: "Messieurs", nationality: "Italie", age: 24, height: "1.92 m", handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/sinner_head_24.png", ranking: 1, points: 8770, strengths: ["Timing de balle parfait", "Revers à deux mains", "Précision chirurgicale", "Résistance physique"], weaknesses: ["Variations de jeu limitées", "Jeu au filet perfectible"], surfaceStats: { clay: { winRate: 0.79 }, hard: { winRate: 0.86 }, grass: { winRate: 0.72 } }, recentForm: ["W", "W", "W", "L", "W"] }, "djokovic": { id: "djokovic", name: "Novak Djokovic", gender: "Messieurs", nationality: "Serbie", age: 39, height: "1.88 m", handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/djokovic_head_24.png", ranking: 4, points: 4200, strengths: ["Retour de service légendaire", "Souplesse défensive", "Expérience tactique", "Mental d'acier"], weaknesses: ["Endurance sur longs matchs", "Démarrage de match poussif"], surfaceStats: { clay: { winRate: 0.80 }, hard: { winRate: 0.84 }, grass: { winRate: 0.85 } }, recentForm: ["W", "L", "W", "W", "L"] }, "ruud": { id: "ruud", name: "Casper Ruud", gender: "Messieurs", nationality: "Norvège", age: 27, height: "1.83 m", handedness: "Droitier", photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/ruud_head_24.png", ranking: 7, points: 3855, strengths: ["Coup droit ultra-lifté", "Stabilité sur terre battue", "Excellente endurance"], weaknesses: ["Revers moins percutant", "Difficulté face aux serveurs volleyeurs"], surfaceStats: { clay: { winRate: 0.81 }, hard: { winRate: 0.64 }, grass: { winRate: 0.52 } }, recentForm: ["W", "L", "W", "L", "W"] }, // ---- SIMPLE DAMES ---- "swiatek": { id: "swiatek", name: "Iga Swiatek", gender: "Dames", nationality: "Pologne", age: 25, height: "1.76 m", handedness: "Droitière", photo: "https://images.prismic.io/wta-assets/f08e7090-ffeb-48b4-82fa-25f00e95ff9d_1_326410_1_15.png", ranking: 1, points: 9450, strengths: ["Lift lourd unique", "Glissades sur terre", "Intensité physique", "Domination du fond de court"], weaknesses: ["Seconde balle de service", "Frustration face aux joueuses ultra-agressives"], surfaceStats: { clay: { winRate: 0.89 }, hard: { winRate: 0.79 }, grass: { winRate: 0.68 } }, recentForm: ["W", "W", "W", "W", "W"] }, "sabalenka": { id: "sabalenka", name: "Aryna Sabalenka", gender: "Dames", nationality: "Biélorussie", age: 28, height: "1.82 m", handedness: "Droitière", photo: "https://images.prismic.io/wta-assets/8a2e1286-90fd-4fbc-bc01-e2518f8892f3_1_324484_1_16.png", ranking: 2, points: 8120, strengths: ["Puissance de frappe brute", "Service dévastateur", "Mental de championne"], weaknesses: ["Fautes directes en cas de frustration", "Mouvements latéraux sur terre battue"], surfaceStats: { clay: { winRate: 0.74 }, hard: { winRate: 0.85 }, grass: { winRate: 0.78 } }, recentForm: ["W", "W", "L", "W", "W"] }, "gauff": { id: "gauff", name: "Coco Gauff", gender: "Dames", nationality: "USA", age: 22, height: "1.75 m", handedness: "Droitière", photo: "https://images.prismic.io/wta-assets/3bc9c6d4-8d48-43e5-83e9-a616715b49ad_1_324749_1_13.png", ranking: 3, points: 6210, strengths: ["Vitesse athlétique exceptionnelle", "Revers régulier", "Excellente au filet"], weaknesses: ["Régularité du coup droit", "Double fautes au service"], surfaceStats: { clay: { winRate: 0.76 }, hard: { winRate: 0.78 }, grass: { winRate: 0.70 } }, recentForm: ["L", "W", "W", "W", "L"] }, "rybakina": { id: "rybakina", name: "Elena Rybakina", gender: "Dames", nationality: "Kazakhstan", age: 27, height: "1.84 m", handedness: "Droitière", photo: "https://images.prismic.io/wta-assets/c81e35d2-a744-4861-b93b-5d9f0003b8cc_1_324166_1_14.png", ranking: 4, points: 5690, strengths: ["Service plat imprenable", "Retour agressif", "Calme olympien"], weaknesses: ["Mobilité réduite dans les rallyes", "Sensibilité aux amorties"], surfaceStats: { clay: { winRate: 0.72 }, hard: { winRate: 0.80 }, grass: { winRate: 0.83 } }, recentForm: ["W", "L", "W", "L", "W"] } }; // Calendrier Officiel Roland Garros 2026 const tournamentMatches = [ { id: 1, round: "Finale Messieurs", gender: "Messieurs", player1: "sinner", player2: "alcaraz", date: "2026-06-07", court: "Court Philippe-Chatrier", status: "upcoming", score: "" }, { id: 2, round: "Finale Dames", gender: "Dames", player1: "swiatek", player2: "sabalenka", date: "2026-06-06", court: "Court Philippe-Chatrier", status: "upcoming", score: "" }, { id: 3, round: "Demi-finale Messieurs", gender: "Messieurs", player1: "alcaraz", player2: "djokovic", date: "2026-06-05", court: "Court Philippe-Chatrier", status: "completed", winner: "alcaraz", score: "6-4, 6-3, 7-5" }, { id: 4, round: "Demi-finale Dames", gender: "Dames", player1: "swiatek", player2: "gauff", date: "2026-06-04", court: "Court Philippe-Chatrier", status: "completed", winner: "swiatek", score: "6-2, 6-4" }, { id: 5, round: "Demi-finale Dames", gender: "Dames", player1: "sabalenka", player2: "rybakina", date: "2026-06-04", court: "Court Suzanne-Lenglen", status: "completed", winner: "sabalenka", score: "7-6, 6-3" } ]; function getPlayerObj(idOrObj) { if (typeof idOrObj === 'object' && idOrObj !== null) return idOrObj; return playersData[idOrObj] || null; } // Algorithme de calcul de probabilités sans faille (basé sur la terre battue) function calculateWinProbability(p1Id, p2Id) { const p1 = getPlayerObj(p1Id); const p2 = getPlayerObj(p2Id); if (!p1 || !p2) return { player1: 50, player2: 50 }; let score1 = 50; let score2 = 50; const rankingDiff = p2.ranking - p1.ranking; score1 += rankingDiff * 1.5; score2 -= rankingDiff * 1.5; const surfaceDiff = (p1.surfaceStats.clay.winRate - p2.surfaceStats.clay.winRate) * 100; score1 += surfaceDiff * 0.4; score2 -= surfaceDiff * 0.4; let finalP1 = Math.round(score1); finalP1 = Math.max(15, Math.min(85, finalP1)); let finalP2 = 100 - finalP1; return { player1: finalP1, player2: finalP2 }; } // Générateur dynamique d'avantages/défauts croisés en fonction de l'opposant function getMatchupAnalysis(p1Id, p2Id) { const p1 = getPlayerObj(p1Id); const p2 = getPlayerObj(p2Id); const analysis = { player1Advantages: [], player1Disadvantages: [], player2Advantages: [], player2Disadvantages: [] }; if (!p1 || !p2) return analysis; if (p1.handedness === "Gaucher" && p2.handedness === "Droitier") { analysis.player1Advantages.push("Effet de service sortant de gaucher gênant le revers adverse"); analysis.player2Disadvantages.push("Doit s'ajuster aux trajectoires spécifiques d'un gaucher"); } const h1 = parseFloat(p1.height); const h2 = parseFloat(p2.height); if (h1 > h2 + 0.05) { analysis.player1Advantages.push("Plus grande allonge au service et angles de frappe plus verticaux"); } else if (h2 > h1 + 0.05) { analysis.player2Advantages.push("Avantage hauteur au service pour trouver des zones plongeantes"); } p1.strengths.forEach(str => { if (p2.weaknesses.some(wk => wk.toLowerCase().includes("fond de court") || wk.toLowerCase().includes("revers"))) { analysis.player1Advantages.push(`Peut pilonner avec son [${str}]`); } }); p2.strengths.forEach(str => { if (p1.weaknesses.some(wk => wk.toLowerCase().includes("fond de court") || wk.toLowerCase().includes("revers"))) { analysis.player2Advantages.push(`Peut pilonner avec son [${str}]`); } }); if (analysis.player1Advantages.length === 0) analysis.player1Advantages.push("Excellente couverture de terrain sur brique pilée"); if (analysis.player2Advantages.length === 0) analysis.player2Advantages.push("Puissance de fond de court régulière"); analysis.player1Disadvantages = p1.weaknesses; analysis.player2Disadvantages = p2.weaknesses; return analysis; }