Pontue uma liga fantasy de MotoGP
Transforme resultados de corridas em pontos fantasy com suas próprias regras de pontuação e classifique as equipes da sua liga após cada etapa.
10 min de leitura
Jogos fantasy são um dos melhores usos dos dados de corridas: os jogadores escolhem pilotos e cada resultado movimenta a tabela da liga. Este guia pontua uma liga em JavaScript com regras que você controla.
As regras
Cada equipe fantasy escolhe três pilotos. Após cada etapa, cada piloto ganha:
| Evento | Pontos fantasy |
|---|---|
| Pontos de campeonato marcados na corrida | 1 por ponto |
| Vitória | +10 de bônus |
| Pódio (P1–P3) | +5 de bônus |
| Não terminou | −5 |
Mantenha as regras como dados, não como código, para poder ajustá-las entre temporadas.
// scoring.js
export const RULES = Object.freeze({
perPoint: 1,
win: 10,
podium: 5,
dnf: -5,
});
/** Fantasy points for one rider's race result. Pure: same input, same output. */
export function scoreResult(result, rules = RULES) {
let score = result.points * rules.perPoint;
if (result.status === "FINISHED") {
if (result.position === 1) score += rules.win;
if (result.position <= 3) score += rules.podium;
} else if (result.status === "DNF") {
score += rules.dnf;
}
return score;
}
Pontue uma etapa
GET /races/seasons/{year}/round/{round}/results retorna uma linha por piloto com position, points, status, rider_name e um rider_id estável. Indexe as linhas por piloto e some as escolhas de cada equipe:
// round.js
import { scoreResult } from "./scoring.js";
const HOST = "motogp-api-championship-data-statistics.p.rapidapi.com";
const headers = { "X-RapidAPI-Key": process.env.RAPIDAPI_KEY, "X-RapidAPI-Host": HOST };
async function get(path) {
const res = await fetch(`https://${HOST}${path}`, { headers });
if (!res.ok) throw new Error(`${path}: ${res.status}`);
return (await res.json()).data;
}
export async function scoreRound(year, round, teams) {
const results = await get(`/races/seasons/${year}/round/${round}/results?category=MOTOGP`);
const byRider = new Map(results.map((r) => [r.rider_name, r]));
return teams
.map((team) => ({
name: team.name,
points: team.riders.reduce((sum, rider) => {
const result = byRider.get(rider);
return sum + (result ? scoreResult(result) : 0); // didn't start: 0
}, 0),
}))
.sort((a, b) => b.points - a.points);
}
const league = [
{ name: "Late Brakers", riders: ["Marco Bezzecchi", "Raúl Fernández", "Fabio Di Giannantonio"] },
{ name: "Apex Hunters", riders: ["Marc Márquez", "Jorge Martín", "Pedro Acosta"] },
];
console.table(await scoreRound(2026, 1, league));
Este exemplo relaciona as escolhas pelo nome para facilitar a leitura. Em produção, guarde o rider_id de cada escolha a partir de GET /riders/seasons/{year} quando o jogador montar sua equipe, e indexe os resultados por rider_id.
Totais da temporada
Pontue cada etapa concluída e some os resultados. Uma etapa que ainda não foi disputada retorna uma lista vazia e pontua 0 para todos:
export async function seasonTable(year, teams, lastRound) {
const totals = new Map(teams.map((t) => [t.name, 0]));
for (let round = 1; round <= lastRound; round++) {
for (const { name, points } of await scoreRound(year, round, teams)) {
totals.set(name, totals.get(name) + points);
}
}
return [...totals].map(([name, points]) => ({ name, points })).sort((a, b) => b.points - a.points);
}
Guarde as pontuações de cada etapa no seu banco de dados assim que os resultados saírem. As pontuações nunca mudam depois que a etapa é finalizada, então você só chama a API para a etapa mais recente.
Listas de escolha e preços
- Quem pode ser escolhido:
GET /riders/seasons/{year}?category=MOTOGPlista o grid da temporada. - Preços dos pilotos: derive-os do campeonato atual —
GET /standings/seasons/{year}/riders— para que os líderes custem mais que os pilotos do fim do grid.