Logo

Randomu' Oltenesc

ARAM Mayhem · Formula V1
Sync App (Windows)
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) — (K+A) / Team Kills
  • 35% Role Performance — se ia cea mai buna metrica din 3 roluri:
    • Damage: Damage Share × 2.5 (cat % din damage-ul echipei ai facut)
    • Tank: Tank Share × 2.5 (cat % din damage taken + mitigated al 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)
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:

Rating = 1.0 + 9.0 × stretch(Composite) + Bonusuri

Rank-normalizare

Fiecare metrica se compara cu toti participantii meciului prin ranking, de la cel mai bun la cel mai slab. 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 }));
  indexed.sort((a, b) => b.v - a.v);
  const scores = new Array(n);
  // damping: N=2 → 0.4, N=3 → 0.6, N=5 → 0.8, N>=8 → ~1.0
  const damping = Math.min(1, 1 - 2 / (n + 1));
  for (let rank = 0; rank < n; rank++) {
    const raw = 1 - (rank / (n - 1));
    scores[indexed[rank].i] = 0.5 + (raw - 0.5) * damping;
  }
  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);
  return Math.max(1.0, Math.min(10.0, Math.round((1.0 + 9.0 * stretched + bonusAdj) * 100) / 100));
}

// ── Raw metrics per participant ──
const raw = participants.map(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 ──
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 * 2.5, // Damage dealer
  r.tank_share * 2.5,   // Tank
  rSupport[i]           // Support (rank-normalized)
));
const impact = 0.40 * r.kp + 0.35 * rolePerf + 0.25 * r.ka_share;

// ═══ 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);