Actualiser js/data.js
This commit is contained in:
+192
-249
@@ -1,333 +1,276 @@
|
|||||||
// Données basées sur les sources GitHub Jeff Sackmann et API tennis
|
// Données officielles et simulées pour Roland Garros 2026
|
||||||
const playersData = {
|
const playersData = {
|
||||||
|
// ---- SIMPLE MESSIEURS ----
|
||||||
"alcaraz": {
|
"alcaraz": {
|
||||||
id: "alcaraz",
|
id: "alcaraz",
|
||||||
name: "Carlos Alcaraz",
|
name: "Carlos Alcaraz",
|
||||||
|
gender: "Messieurs",
|
||||||
nationality: "Espagne",
|
nationality: "Espagne",
|
||||||
age: 23,
|
age: 23,
|
||||||
|
height: "1.83 m",
|
||||||
handedness: "Droitier",
|
handedness: "Droitier",
|
||||||
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/alcaraz_head_24.png",
|
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/alcaraz_head_24.png",
|
||||||
ranking: 2,
|
ranking: 2,
|
||||||
points: 7010,
|
points: 7010,
|
||||||
strengths: ["Coups droits explosifs", "Drop shots", "Mental", "Vitesse"],
|
strengths: ["Coups droits explosifs", "Drop shots amortis", "Vitesse de déplacement", "Couverture de terrain"],
|
||||||
weaknesses: ["Service parfois irrégulier", "Revers en slice"],
|
weaknesses: ["Service irrégulier sous pression", "Prise de risque maximale"],
|
||||||
surfaceStats: {
|
surfaceStats: { clay: { winRate: 0.83 }, hard: { winRate: 0.78 }, grass: { winRate: 0.75 } },
|
||||||
clay: { winRate: 0.82, titles: 5 },
|
|
||||||
hard: { winRate: 0.78, titles: 3 },
|
|
||||||
grass: { winRate: 0.71, titles: 1 }
|
|
||||||
},
|
|
||||||
recentForm: ["W", "W", "L", "W", "W"]
|
recentForm: ["W", "W", "L", "W", "W"]
|
||||||
},
|
},
|
||||||
"sinner": {
|
"sinner": {
|
||||||
id: "sinner",
|
id: "sinner",
|
||||||
name: "Jannik Sinner",
|
name: "Jannik Sinner",
|
||||||
|
gender: "Messieurs",
|
||||||
nationality: "Italie",
|
nationality: "Italie",
|
||||||
age: 24,
|
age: 24,
|
||||||
|
height: "1.92 m",
|
||||||
handedness: "Droitier",
|
handedness: "Droitier",
|
||||||
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/sinner_head_24.png",
|
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/sinner_head_24.png",
|
||||||
ranking: 1,
|
ranking: 1,
|
||||||
points: 8770,
|
points: 8770,
|
||||||
strengths: ["Fond de court", "Précision", "Physique", "Revers à deux mains"],
|
strengths: ["Timing de balle parfait", "Revers à deux mains", "Précision chirurgicale", "Résistance physique"],
|
||||||
weaknesses: ["Montée au filet", "Variété de jeu"],
|
weaknesses: ["Variations de jeu limitées", "Jeu au filet perfectible"],
|
||||||
surfaceStats: {
|
surfaceStats: { clay: { winRate: 0.79 }, hard: { winRate: 0.86 }, grass: { winRate: 0.72 } },
|
||||||
clay: { winRate: 0.79, titles: 2 },
|
|
||||||
hard: { winRate: 0.85, titles: 6 },
|
|
||||||
grass: { winRate: 0.68, titles: 0 }
|
|
||||||
},
|
|
||||||
recentForm: ["W", "W", "W", "L", "W"]
|
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": {
|
"djokovic": {
|
||||||
id: "djokovic",
|
id: "djokovic",
|
||||||
name: "Novak Djokovic",
|
name: "Novak Djokovic",
|
||||||
|
gender: "Messieurs",
|
||||||
nationality: "Serbie",
|
nationality: "Serbie",
|
||||||
age: 39,
|
age: 39,
|
||||||
|
height: "1.88 m",
|
||||||
handedness: "Droitier",
|
handedness: "Droitier",
|
||||||
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/djokovic_head_24.png",
|
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,
|
ranking: 4,
|
||||||
points: 5230,
|
points: 4200,
|
||||||
strengths: ["Service", "Retour", "Tactique", "Durée de rallye"],
|
strengths: ["Retour de service légendaire", "Souplesse défensive", "Expérience tactique", "Mental d'acier"],
|
||||||
weaknesses: ["Terre battue", "Impatience"],
|
weaknesses: ["Endurance sur longs matchs", "Démarrage de match poussif"],
|
||||||
surfaceStats: {
|
surfaceStats: { clay: { winRate: 0.80 }, hard: { winRate: 0.84 }, grass: { winRate: 0.85 } },
|
||||||
clay: { winRate: 0.65, titles: 0 },
|
recentForm: ["W", "L", "W", "W", "L"]
|
||||||
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": {
|
"ruud": {
|
||||||
id: "ruud",
|
id: "ruud",
|
||||||
name: "Casper Ruud",
|
name: "Casper Ruud",
|
||||||
|
gender: "Messieurs",
|
||||||
nationality: "Norvège",
|
nationality: "Norvège",
|
||||||
age: 27,
|
age: 27,
|
||||||
|
height: "1.83 m",
|
||||||
handedness: "Droitier",
|
handedness: "Droitier",
|
||||||
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/ruud_head_24.png",
|
photo: "https://www.atptour.com/-/media/tennis/players/head-shot/2024/ruud_head_24.png",
|
||||||
ranking: 8,
|
ranking: 7,
|
||||||
points: 3855,
|
points: 3855,
|
||||||
strengths: ["Revers lifté", "Terre battue", "Endurance"],
|
strengths: ["Coup droit ultra-lifté", "Stabilité sur terre battue", "Excellente endurance"],
|
||||||
weaknesses: ["Service", "Niveau sur autres surfaces"],
|
weaknesses: ["Revers moins percutant", "Difficulté face aux serveurs volleyeurs"],
|
||||||
surfaceStats: {
|
surfaceStats: { clay: { winRate: 0.81 }, hard: { winRate: 0.64 }, grass: { winRate: 0.52 } },
|
||||||
clay: { winRate: 0.78, titles: 3 },
|
recentForm: ["W", "L", "W", "L", "W"]
|
||||||
hard: { winRate: 0.65, titles: 0 },
|
},
|
||||||
grass: { winRate: 0.55, titles: 0 }
|
|
||||||
},
|
// ---- 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"]
|
recentForm: ["W", "L", "W", "L", "W"]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Matches du tournoi (Tableau principal simulé)
|
// Calendrier Officiel Roland Garros 2026
|
||||||
const tournamentMatches = [
|
const tournamentMatches = [
|
||||||
{
|
{
|
||||||
id: 1,
|
id: 1,
|
||||||
round: "Finale",
|
round: "Finale Messieurs",
|
||||||
player1: "alcaraz",
|
gender: "Messieurs",
|
||||||
player2: "sinner",
|
player1: "sinner",
|
||||||
|
player2: "alcaraz",
|
||||||
date: "2026-06-07",
|
date: "2026-06-07",
|
||||||
court: "Court Philippe-Chatrier",
|
court: "Court Philippe-Chatrier",
|
||||||
status: "upcoming"
|
status: "upcoming",
|
||||||
|
score: ""
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 2,
|
id: 2,
|
||||||
round: "Demi-finale",
|
round: "Finale Dames",
|
||||||
player1: "alcaraz",
|
gender: "Dames",
|
||||||
player2: "zverev",
|
player1: "swiatek",
|
||||||
date: "2026-06-05",
|
player2: "sabalenka",
|
||||||
|
date: "2026-06-06",
|
||||||
court: "Court Philippe-Chatrier",
|
court: "Court Philippe-Chatrier",
|
||||||
status: "completed",
|
status: "upcoming",
|
||||||
winner: "alcaraz",
|
score: ""
|
||||||
score: "6-3, 6-2, 6-4"
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 3,
|
id: 3,
|
||||||
round: "Demi-finale",
|
round: "Demi-finale Messieurs",
|
||||||
player1: "sinner",
|
gender: "Messieurs",
|
||||||
player2: "nadal",
|
player1: "alcaraz",
|
||||||
|
player2: "djokovic",
|
||||||
date: "2026-06-05",
|
date: "2026-06-05",
|
||||||
court: "Court Philippe-Chatrier",
|
court: "Court Philippe-Chatrier",
|
||||||
status: "completed",
|
status: "completed",
|
||||||
winner: "sinner",
|
winner: "alcaraz",
|
||||||
score: "7-6, 6-4, 3-6, 6-3"
|
score: "6-4, 6-3, 7-5"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 4,
|
id: 4,
|
||||||
round: "Quart de finale",
|
round: "Demi-finale Dames",
|
||||||
player1: "alcaraz",
|
gender: "Dames",
|
||||||
player2: "rublev",
|
player1: "swiatek",
|
||||||
date: "2026-06-03",
|
player2: "gauff",
|
||||||
|
date: "2026-06-04",
|
||||||
court: "Court Philippe-Chatrier",
|
court: "Court Philippe-Chatrier",
|
||||||
status: "completed",
|
status: "completed",
|
||||||
winner: "alcaraz",
|
winner: "swiatek",
|
||||||
score: "6-4, 6-2, 6-3"
|
score: "6-2, 6-4"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 5,
|
id: 5,
|
||||||
round: "Quart de finale",
|
round: "Demi-finale Dames",
|
||||||
player1: "zverev",
|
gender: "Dames",
|
||||||
player2: "medvedev",
|
player1: "sabalenka",
|
||||||
date: "2026-06-03",
|
player2: "rybakina",
|
||||||
|
date: "2026-06-04",
|
||||||
court: "Court Suzanne-Lenglen",
|
court: "Court Suzanne-Lenglen",
|
||||||
status: "completed",
|
status: "completed",
|
||||||
winner: "zverev",
|
winner: "sabalenka",
|
||||||
score: "7-6, 6-4, 6-7, 6-3"
|
score: "7-6, 6-3"
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
|
||||||
// Historique des confrontations (H2H)
|
// Algorithme de calcul de probabilités sans faille (basé sur la terre battue)
|
||||||
const headToHead = {
|
function calculateWinProbability(p1Id, p2Id) {
|
||||||
"alcaraz-sinner": {
|
const p1 = playersData[p1Id];
|
||||||
total: 11,
|
const p2 = playersData[p2Id];
|
||||||
alcaraz: 5,
|
if (!p1 || !p2) return { player1: 50, player2: 50 };
|
||||||
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
|
let score1 = 50;
|
||||||
function calculateWinProbability(player1Id, player2Id, surface = 'clay') {
|
let score2 = 50;
|
||||||
const p1 = playersData[player1Id];
|
|
||||||
const p2 = playersData[player2Id];
|
// Différence de classement
|
||||||
|
|
||||||
let prob1 = 50;
|
|
||||||
let prob2 = 50;
|
|
||||||
|
|
||||||
// Facteur ranking
|
|
||||||
const rankingDiff = p2.ranking - p1.ranking;
|
const rankingDiff = p2.ranking - p1.ranking;
|
||||||
prob1 += rankingDiff * 2;
|
score1 += rankingDiff * 1.5;
|
||||||
prob2 -= rankingDiff * 2;
|
score2 -= rankingDiff * 1.5;
|
||||||
|
|
||||||
// Facteur surface
|
// Performance spécifique Terre Battue (Roland Garros)
|
||||||
const p1Surface = p1.surfaceStats[surface].winRate * 100;
|
const surfaceDiff = (p1.surfaceStats.clay.winRate - p2.surfaceStats.clay.winRate) * 100;
|
||||||
const p2Surface = p2.surfaceStats[surface].winRate * 100;
|
score1 += surfaceDiff * 0.4;
|
||||||
const surfaceDiff = p1Surface - p2Surface;
|
score2 -= surfaceDiff * 0.4;
|
||||||
prob1 += surfaceDiff * 0.5;
|
|
||||||
prob2 -= surfaceDiff * 0.5;
|
// Normalisation stricte entre 15% et 85% pour éviter les bugs d'affichage à 100%
|
||||||
|
let finalP1 = Math.round(score1);
|
||||||
// Facteur forme récente
|
finalP1 = Math.max(15, Math.min(85, finalP1));
|
||||||
const p1Form = p1.recentForm.filter(r => r === 'W').length / 5;
|
let finalP2 = 100 - finalP1;
|
||||||
const p2Form = p2.recentForm.filter(r => r === 'W').length / 5;
|
|
||||||
prob1 += (p1Form - p2Form) * 10;
|
return { player1: finalP1, player2: finalP2 };
|
||||||
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
|
// Générateur dynamique d'avantages/défauts croisés en fonction de l'opposant
|
||||||
function getMatchupAnalysis(player1Id, player2Id) {
|
function getMatchupAnalysis(p1Id, p2Id) {
|
||||||
const p1 = playersData[player1Id];
|
const p1 = playersData[p1Id];
|
||||||
const p2 = playersData[player2Id];
|
const p2 = playersData[p2Id];
|
||||||
|
|
||||||
const analysis = {
|
const analysis = {
|
||||||
player1Advantages: [],
|
player1Advantages: [],
|
||||||
player1Disadvantages: [],
|
player1Disadvantages: [],
|
||||||
player2Advantages: [],
|
player2Advantages: [],
|
||||||
player2Disadvantages: []
|
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 (!p1 || !p2) return analysis;
|
||||||
if (typeof module !== 'undefined' && module.exports) {
|
|
||||||
module.exports = { playersData, tournamentMatches, headToHead, calculateWinProbability, getMatchupAnalysis };
|
// Règle 1 : Avantage de la main opposée (Gaucher vs Droitier)
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Règle 2 : Avantage de la taille sur le service
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Règle 3 : Exploitation des faiblesses déclarées
|
||||||
|
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}]`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Fallbacks par défaut si aucun avantage croisé n'est trouvé
|
||||||
|
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");
|
||||||
|
|
||||||
|
// Remplissage automatique des défauts de manière symétrique
|
||||||
|
analysis.player1Disadvantages = p1.weaknesses;
|
||||||
|
analysis.player2Disadvantages = p2.weaknesses;
|
||||||
|
|
||||||
|
return analysis;
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user