← 모든 가이드

MotoGP 판타지 리그 점수 계산하기

직접 정한 점수 규칙으로 레이스 결과를 판타지 포인트로 바꾸고, 매 라운드 후 리그의 팀 순위를 매깁니다.

10분 분량

판타지 게임은 레이스 데이터의 가장 좋은 활용처 중 하나입니다. 플레이어가 라이더를 고르고, 결과가 나올 때마다 리그 순위표가 바뀝니다. 이 가이드는 직접 제어할 수 있는 규칙으로 JavaScript에서 리그 점수를 계산합니다.

규칙

각 판타지 팀은 라이더 세 명을 선택합니다. 매 라운드 후 각 라이더는 다음 점수를 얻습니다.

이벤트판타지 포인트
레이스에서 얻은 챔피언십 포인트포인트당 1
우승+10 보너스
포디움(P1–P3)+5 보너스
리타이어−5

규칙은 코드가 아니라 데이터로 두면 시즌 사이에 조정하기 쉽습니다.

// 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;
}

라운드 점수 계산

GET /races/seasons/{year}/round/{round}/results는 라이더당 한 행씩 position, points, status, rider_name, 그리고 변하지 않는 rider_id를 반환합니다. 행을 라이더별로 인덱싱하고 각 팀이 고른 라이더의 점수를 합산하세요.

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

이 예제는 가독성을 위해 이름으로 선택을 매칭합니다. 실제 서비스에서는 플레이어가 팀을 만들 때 GET /riders/seasons/{year}에서 각 선택의 rider_id를 저장하고, 결과를 rider_id로 인덱싱하세요.

시즌 합계

종료된 모든 라운드의 점수를 계산해 합산합니다. 아직 열리지 않은 라운드는 빈 목록을 반환하며 모두에게 0점으로 계산됩니다.

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);
}

결과가 나오면 각 라운드의 점수를 데이터베이스에 저장하세요. 라운드가 확정된 후에는 점수가 바뀌지 않으므로, API는 가장 최근 라운드에 대해서만 호출하면 됩니다.

선택 목록과 가격 책정

  • 선택 가능한 라이더: GET /riders/seasons/{year}?category=MOTOGP로 시즌 그리드를 조회합니다.
  • 라이더 가격: 현재 챔피언십(GET /standings/seasons/{year}/riders)에서 가격을 산출해 선두 라이더가 하위권 라이더보다 비싸게 합니다.