Crowd Pick 비율 합이 항상 100% 되도록 반올림 보정
parent
0a64a220ca
commit
8580bbb713
|
|
@ -1,5 +1,5 @@
|
|||
import { useEffect, useMemo, useState } from "react";
|
||||
import { outcomeLabel, pct, kickoffDisplay, winProb } from "@/lib/format";
|
||||
import { outcomeLabel, pctParts, kickoffDisplay, winProb } from "@/lib/format";
|
||||
import { type Lang, dict, teamShort } from "@/lib/i18n";
|
||||
import type {
|
||||
Outcome,
|
||||
|
|
@ -542,15 +542,15 @@ export default function Arena({
|
|||
Crowd Pick{" "}
|
||||
<span className="text-[14px] text-[var(--ink-muted)]">{t.crowdSub}</span>
|
||||
</div>
|
||||
{/* 비율은 분포 합 기준(=total 과 동일해야 정상) — 구 데이터 불일치 시에도 100% 이내로 표시 */}
|
||||
{/* 비율은 분포 합 기준 + 합이 항상 100% 되도록 보정(최대 잔여 방식) */}
|
||||
<div className="flex h-14 overflow-hidden rounded-2xl border border-[var(--line-d)]">
|
||||
{(() => {
|
||||
const sum = crowd.teamAWin + crowd.draw + crowd.teamBWin;
|
||||
const [a, d, b] = pctParts([crowd.teamAWin, crowd.draw, crowd.teamBWin]);
|
||||
return (
|
||||
<>
|
||||
<CrowdSeg team={match.teamA} value={pct(crowd.teamAWin, sum)} tone="a" />
|
||||
<CrowdSeg value={pct(crowd.draw, sum)} tone="draw" />
|
||||
<CrowdSeg team={match.teamB} value={pct(crowd.teamBWin, sum)} tone="b" />
|
||||
<CrowdSeg team={match.teamA} value={a} tone="a" />
|
||||
<CrowdSeg value={d} tone="draw" />
|
||||
<CrowdSeg team={match.teamB} value={b} tone="b" />
|
||||
</>
|
||||
);
|
||||
})()}
|
||||
|
|
|
|||
|
|
@ -55,6 +55,27 @@ export function pct(part: number, total: number): number {
|
|||
return Math.round((part / total) * 100);
|
||||
}
|
||||
|
||||
// 여러 비율을 정수 %로 — 합이 항상 정확히 100 (최대 잔여 방식).
|
||||
// 각자 따로 반올림하면 99/101 이 나오는 문제를 방지.
|
||||
export function pctParts(parts: number[]): number[] {
|
||||
const total = parts.reduce((s, p) => s + p, 0);
|
||||
if (!total) return parts.map(() => 0);
|
||||
const raw = parts.map((p) => (p / total) * 100);
|
||||
const floor = raw.map(Math.floor);
|
||||
let remainder = 100 - floor.reduce((s, v) => s + v, 0);
|
||||
// 소수부가 큰 순서로 남은 %를 1씩 분배
|
||||
const order = raw
|
||||
.map((v, i) => ({ i, frac: v - Math.floor(v) }))
|
||||
.sort((a, b) => b.frac - a.frac);
|
||||
const out = [...floor];
|
||||
for (const { i } of order) {
|
||||
if (remainder <= 0) break;
|
||||
out[i] += 1;
|
||||
remainder -= 1;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// "방금 전 / 3분 전 / 2시간 전 / 5일 전" — 댓글 상대시간
|
||||
export function relativeTime(iso: string, lang: Lang = "ko"): string {
|
||||
const then = new Date(iso).getTime();
|
||||
|
|
|
|||
Loading…
Reference in New Issue