Stema Randomu' Oltenesc

Randomu' Oltenesc

ARAM Mayhem
OltenizerWindows · Descarcă
Se incarca...

Cum se calculeaza ratingul

Scor Compozit (calculat in timp real)

Rating-ul se calculeaza din datele raw ale meciului, comparat cu toti participantii prin rank-normalizare. Formula e role-agnostic — tank, support, ADC sau fighter sunt evaluate echitabil. Nu exista bonus/penalizare pentru victorie/infrangere — scopul e masurarea contributiei individuale pentru echilibrarea echipelor.

Impact 70%
  • 40% Kill Participation (KP) — scor continuu: 0.5 + KP − media KP din meci, limitat intre 0 si 1
  • 35% Role Performance — se ia cea mai buna metrica din 3 roluri:
    • Damage: Damage Share × N / 2 (N = numarul de jucatori din echipa ta)
    • Tank: Tank Share × N / 2 (damage taken + mitigated, ajustat la marimea echipei)
    • Support: Healing + CC Score × 100, rank-normalizat
    Role Performance are soft-cap la 1.2, astfel incat prestatiile extreme raman diferentiate.
  • 25% Kill/Assist Share — (K+A) / Team (K+A) × N / 5
Supravietuire 15%
  • KDA Ratio: (K+A) / (D+1), rank-normalizat in meci
  • Ponderea redusa (15%) ca sa nu penalizeze tankii care fac engage
Eficienta 15%
  • max(Damage/Gold, CC/Gold), rank-normalizat
  • Damage dealers primesc credit pentru DPG, tankii/supportii pentru CC/Gold

Formula

Composite = 0.70×Impact + 0.15×Supravietuire + 0.15×Eficienta

Se aplica o functie de stretch (exponent 0.65) pentru a pastra diferente clare fara a impinge excesiv notele spre 1 sau 10:

S = stretch(Composite); Rating = 1.0 + 9.0 × (3S / (1 + 2S)) + Bonusuri

Aceasta calibrare foloseste aceeasi scala pentru toate formatele: scorul neutru 0.5 devine nota 7.75. Curba pastreaza ordinea performantelor; notele slabe pot ramane sub 5, iar capetele scalei raman 1 si 10.

Participare si rank-normalizare

KP = (K+A) / killurile echipei. Media KP a meciului primeste scorul 0.5; diferentele reale fata de medie se pastreaza, fara salturi de clasament. Un procent apropiat de al altui jucator produce un punctaj apropiat, indiferent de ordinea lor.

KDA, support si eficienta se compara cu toti participantii meciului prin ranking, de la cel mai bun la cel mai slab. Valorile egale primesc acelasi punctaj. Damage, tanking si kill/assist share sunt ajustate la marimea propriei echipe, cu 5vs5 ca referinta. Damping-ul trage capetele clasamentului catre 0.5 in meciurile cu putini jucatori, pentru a evita extremele. Asta inseamna ca un meci de 3v3 nu va produce rating-uri la fel de polarizate ca un 5v5.

Bonusuri & Penalizari

Bonusurile si penalizarile sunt dezactivate temporar. Regulile sunt pastrate mai jos pentru reactivare ulterioara.

Bonusuri — dezactivate temporar
  • +0.60 "The Carry" — Rank 1 Damage si KP de minimum 65%
  • +0.30 "Hard Carry / 1v9" — Rank 1 Damage cu peste 40% mai mult damage decat locul 2
  • +0.40 "Smart Player" — Cele mai putine deaths + KP > 50%
  • +0.40 "The Frontline" — Most damage taken + KP > 40% — recompenseaza tankii care fac engage si participa activ
Penalizari — dezactivate temporar
  • -1.50 "The Passenger" — KP sub 45% + cel mai mic damage, cu protectie pentru frontline/healer
  • -0.70 "Gold Sink" — Rank 1 Gold + damage share sub 35%, cu protectie pentru frontline/healer
  • -0.50 "Dead Weight" — cele mai multe deaths + KP sub 80% + damage share sub 20%, cu protectie pentru frontline/healer

Ce NU afecteaza ratingul

  • Victoria/Infrangerea — nu exista bonus de win/loss. Rating-ul masoara contributia individuala, nu rezultatul meciului. Asta previne feedback loop-ul unde jucatorii cu rating mare ajung in echipe mai bune, castiga, si primesc rating si mai mare.

De ce e fair pentru orice rol?

  • Tank — primeste credit prin Tank Share (Impact), bonus "The Frontline", si Survival redus la 15% ca sa nu fie penalizat pentru deaths inevitabile din engage
  • Support — primeste credit prin Support Score (healing + CC), protejat de penalizarile "Passenger" si "Gold Sink" daca are healing/CC ridicat
  • ADC/Mage — primeste credit prin Damage Share si Damage/Gold efficiency
  • Fighter/Bruiser — beneficiaza de mix: damage share, tank share, si KP ridicat

Rating overall

Tabul Last 10 Games foloseste ultimele 10 meciuri. Tabul Overall foloseste ultimele maximum 100 de meciuri per player, cu minimum 10 meciuri pentru eligibilitate.

Codul sursa

// ── Rank-normalizare ──
function rankNormalize(values) {
  const n = values.length;
  if (n <= 1) return values.map(() => 0.5);
  const indexed = values.map((v, i) => ({ v, i })).sort((a, b) => b.v - a.v);
  const scores = new Array(n);
  const damping = Math.min(1, 1 - 2 / (n + 1));
  // Tied values share their average rank, independent of participant order.
  for (let start = 0; start < n;) {
    let end = start + 1;
    while (end < n && indexed[end].v === indexed[start].v) end++;
    const raw = 1 - ((start + end - 1) / 2) / (n - 1);
    const score = 0.5 + (raw - 0.5) * damping;
    for (let rank = start; rank < end; rank++) scores[indexed[rank].i] = score;
    start = end;
  }
  return scores;
}

// ── Stretch + Rating ──
function stretchFromCenter(value, exp) {
  if (value < 0.5) return 0.5 - Math.pow((0.5 - value) / 0.5, exp) * 0.5;
  return 0.5 + Math.pow((value - 0.5) / 0.5, exp) * 0.5;
}

function compositeToRating(composite, bonusAdj) {
  const stretched = stretchFromCenter(Math.max(0, Math.min(1, composite)), 0.65);
  const calibrated = (3 * stretched) / (1 + 2 * stretched);
  return Math.max(1.0, Math.min(10.0, Math.round((1.0 + 9.0 * calibrated + bonusAdj) * 100) / 100));
}

// ── Raw metrics per participant ──
const raw = participants.map(p => ({
  team_size:       teamSize, // numarul de jucatori din echipa lui p
  kp:              Math.min(1, (p.kills + p.assists) / teamKills),
  damage_share:    p.damage / teamDamage,
  tank_share:      (p.damage_taken + p.self_mitigated) / teamTakenMit,
  support_metric:  p.healing + p.cc_score * 100,
  ka_share:        (p.kills + p.assists) / teamKA,
  kda:             (p.kills + p.assists) / (p.deaths + 1),
  damage_per_gold: p.damage / p.gold,
  cc_per_gold:     p.cc_score / p.gold,
  damage:          p.damage,
  gold:            p.gold,
  deaths:          p.deaths,
  damage_taken:    p.damage_taken,
  self_mitigated:  p.self_mitigated,
}));

// ── Rank-normalize all metrics ──
// KP pastreaza distantele reale fata de media meciului, fara ranking.
const kpBaseline = raw.reduce((sum, r) => sum + r.kp, 0) / raw.length;
const kpScores = raw.map(r => Math.max(0, Math.min(1, 0.5 + r.kp - kpBaseline)));
const rSupport     = rankNormalize(raw.map(r => r.support_metric));
const rKda         = rankNormalize(raw.map(r => r.kda));
const rDmgPerGold  = rankNormalize(raw.map(r => r.damage_per_gold));
const rCcPerGold   = rankNormalize(raw.map(r => r.cc_per_gold));
const rGold        = rankNormalize(raw.map(r => r.gold));
const rHealing     = rankNormalize(raw.map(r => r.support_metric));

// ═══ 1. IMPACT (70%) ═══
const rolePerf = Math.min(1.2, Math.max(
  r.damage_share * r.team_size / 2, // Damage dealer
  r.tank_share * r.team_size / 2,   // Tank
  rSupport[i]           // Support (rank-normalized)
));
const kaScore = r.ka_share * r.team_size / 5;
const impact = 0.40 * kpScores[i] + 0.35 * rolePerf + 0.25 * kaScore;

// ═══ 2. SURVIVAL (15%) ═══
const survival = rKda[i];

// ═══ 3. EFFICIENCY (15%) ═══
const efficiency = Math.max(rDmgPerGold[i], rCcPerGold[i]);

// ═══ Composite ═══
let composite = 0.70 * impact + 0.15 * survival + 0.15 * efficiency;

// ═══ Bonusuri & Penalizari ═══
const highestDmg = Math.max(...participants.map(p => p.damage));
const lowerDamage = participants.map(p => p.damage).filter(d => d < highestDmg);
const secondHighestDmg = lowerDamage.length ? Math.max(...lowerDamage) : null;
const rank1Damage = p.damage === highestDmg;
const fewestDeaths = p.deaths === Math.min(...participants.map(p => p.deaths));
const mostTakenMitigated = p.damage_taken + p.self_mitigated === Math.max(
  ...participants.map(p => p.damage_taken + p.self_mitigated)
);
const topGold = rGold[i] === Math.max(...rGold);
const bottomDamage = p.damage === Math.min(...participants.map(p => p.damage));
const mostDeaths = p.deaths === Math.max(...participants.map(p => p.deaths));
const isHealer = rHealing[i] >= 0.75;
const isFrontline = r.tank_share >= 0.30;
const isProtected = isHealer || isFrontline;

// ── Bonusuri dezactivate temporar ──
// if (rank1Damage && r.kp >= 0.65) bonus += 0.60; // The Carry
// if (rank1Damage && secondHighestDmg !== null
//     && highestDmg > secondHighestDmg * 1.4) bonus += 0.30; // Hard Carry / 1v9
// if (fewestDeaths && r.kp > 0.50) bonus += 0.40; // Smart Player
// if (mostTakenMitigated && r.kp > 0.40) bonus += 0.40; // The Frontline

// ── Penalizari dezactivate temporar ──
// if (r.kp < 0.45 && bottomDamage && !isProtected) bonus -= 1.50; // Passenger
// if (topGold && r.damage_share < 0.35 && !isProtected) bonus -= 0.70; // Gold Sink
// if (mostDeaths && r.kp < 0.80 && r.damage_share < 0.20 && !isProtected) bonus -= 0.50; // Dead Weight

// ═══ Final Rating (1-10) ═══
rating = compositeToRating(composite, bonus);