Crowd Pick 비율 합이 항상 100% 되도록 반올림 보정
parent
0a64a220ca
commit
8580bbb713
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useMemo, useState } from "react";
|
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 Lang, dict, teamShort } from "@/lib/i18n";
|
||||||
import type {
|
import type {
|
||||||
Outcome,
|
Outcome,
|
||||||
|
|
@ -542,15 +542,15 @@ export default function Arena({
|
||||||
Crowd Pick{" "}
|
Crowd Pick{" "}
|
||||||
<span className="text-[14px] text-[var(--ink-muted)]">{t.crowdSub}</span>
|
<span className="text-[14px] text-[var(--ink-muted)]">{t.crowdSub}</span>
|
||||||
</div>
|
</div>
|
||||||
{/* 비율은 분포 합 기준(=total 과 동일해야 정상) — 구 데이터 불일치 시에도 100% 이내로 표시 */}
|
{/* 비율은 분포 합 기준 + 합이 항상 100% 되도록 보정(최대 잔여 방식) */}
|
||||||
<div className="flex h-14 overflow-hidden rounded-2xl border border-[var(--line-d)]">
|
<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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<CrowdSeg team={match.teamA} value={pct(crowd.teamAWin, sum)} tone="a" />
|
<CrowdSeg team={match.teamA} value={a} tone="a" />
|
||||||
<CrowdSeg value={pct(crowd.draw, sum)} tone="draw" />
|
<CrowdSeg value={d} tone="draw" />
|
||||||
<CrowdSeg team={match.teamB} value={pct(crowd.teamBWin, sum)} tone="b" />
|
<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);
|
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일 전" — 댓글 상대시간
|
// "방금 전 / 3분 전 / 2시간 전 / 5일 전" — 댓글 상대시간
|
||||||
export function relativeTime(iso: string, lang: Lang = "ko"): string {
|
export function relativeTime(iso: string, lang: Lang = "ko"): string {
|
||||||
const then = new Date(iso).getTime();
|
const then = new Date(iso).getTime();
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue