aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx')
-rw-r--r--frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx191
1 files changed, 167 insertions, 24 deletions
diff --git a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
index 22277f8..53d5bce 100644
--- a/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
+++ b/frontend/app/components/GolfWatchApps/GolfWatchAppGaming.tsx
@@ -1,41 +1,184 @@
+import ExecStatusIndicatorIcon from "../ExecStatusIndicatorIcon";
+
type Props = {
problem: string;
- codeA: string;
- scoreA: number | null;
- codeB: string;
- scoreB: number | null;
+ playerInfoA: PlayerInfo;
+ playerInfoB: PlayerInfo;
+ leftTimeSeconds: number;
+};
+
+export type PlayerInfo = {
+ displayName: string | null;
+ iconPath: string | null;
+ score: number | null;
+ code: string | null;
+ submissionResult?: SubmissionResult;
+};
+
+type SubmissionResult = {
+ status:
+ | "running"
+ | "success"
+ | "wrong_answer"
+ | "timeout"
+ | "compile_error"
+ | "runtime_error"
+ | "internal_error";
+ preliminaryScore: number;
+ verificationResults: VerificationResult[];
};
+type VerificationResult = {
+ testcase_id: number | null;
+ status:
+ | "running"
+ | "success"
+ | "wrong_answer"
+ | "timeout"
+ | "compile_error"
+ | "runtime_error"
+ | "internal_error"
+ | "canceled";
+ label: string;
+ stdout: string;
+ stderr: string;
+};
+
+function submissionResultStatusToLabel(
+ status: SubmissionResult["status"] | null,
+) {
+ switch (status) {
+ case null:
+ return "-";
+ case "running":
+ return "Running...";
+ case "success":
+ return "Accepted";
+ case "wrong_answer":
+ return "Wrong Answer";
+ case "timeout":
+ return "Time Limit Exceeded";
+ case "compile_error":
+ return "Compile Error";
+ case "runtime_error":
+ return "Runtime Error";
+ case "internal_error":
+ return "Internal Error";
+ }
+}
+
export default function GolfWatchAppGaming({
problem,
- codeA,
- scoreA,
- codeB,
- scoreB,
+ playerInfoA,
+ playerInfoB,
+ leftTimeSeconds,
}: Props) {
+ const leftTime = (() => {
+ const m = Math.floor(leftTimeSeconds / 60);
+ const s = leftTimeSeconds % 60;
+ return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
+ })();
+ const scoreRatio = (() => {
+ const scoreA = playerInfoA.score ?? 0;
+ const scoreB = playerInfoB.score ?? 0;
+ const totalScore = scoreA + scoreB;
+ return totalScore === 0 ? 50 : (scoreB / totalScore) * 100;
+ })();
+
return (
- <div style={{ display: "flex", flexDirection: "column" }}>
- <div style={{ display: "flex", flex: 1, justifyContent: "center" }}>
- <div>{problem}</div>
+ <div className="grid h-full w-full grid-rows-[auto_auto_1fr_auto]">
+ <div className="grid grid-cols-[1fr_auto_1fr]">
+ <div className="grid justify-start bg-red-500 p-2 text-white">
+ {playerInfoA.displayName}
+ </div>
+ <div className="grid justify-center p-2">{leftTime}</div>
+ <div className="grid justify-end bg-blue-500 p-2 text-white">
+ {playerInfoB.displayName}
+ </div>
+ </div>
+ <div className="grid grid-cols-[auto_1fr_auto]">
+ <div className="grid justify-start bg-red-500 p-2 text-lg font-bold text-white">
+ {playerInfoA.score ?? "-"}
+ </div>
+ <div className="w-full bg-blue-500">
+ <div
+ className="h-full bg-red-500"
+ style={{ width: `${scoreRatio}%` }}
+ ></div>
+ </div>
+ <div className="grid justify-end bg-blue-500 p-2 text-lg font-bold text-white">
+ {playerInfoB.score ?? "-"}
+ </div>
</div>
- <div style={{ display: "flex", flex: 3 }}>
- <div style={{ display: "flex", flex: 3, flexDirection: "column" }}>
- <div style={{ flex: 1, justifyContent: "center" }}>{scoreA}</div>
- <div style={{ flex: 3 }}>
- <pre>
- <code>{codeA}</code>
- </pre>
+ <div className="grid grid-cols-[3fr_2fr_3fr_2fr] p-2">
+ <div>
+ <pre>
+ <code>{playerInfoA.code}</code>
+ </pre>
+ </div>
+ <div>
+ <div>
+ {submissionResultStatusToLabel(
+ playerInfoA.submissionResult?.status ?? null,
+ )}{" "}
+ ({playerInfoA.submissionResult?.preliminaryScore})
+ </div>
+ <div>
+ <ol>
+ {playerInfoA.submissionResult?.verificationResults.map(
+ (result, idx) => (
+ <li key={idx}>
+ <div>
+ <div>
+ <ExecStatusIndicatorIcon status={result.status} />{" "}
+ {result.label}
+ </div>
+ <div>
+ {result.stdout}
+ {result.stderr}
+ </div>
+ </div>
+ </li>
+ ),
+ )}
+ </ol>
</div>
</div>
- <div style={{ display: "flex", flex: 3, flexDirection: "column" }}>
- <div style={{ flex: 1, justifyContent: "center" }}>{scoreB}</div>
- <div style={{ flex: 3 }}>
- <pre>
- <code>{codeB}</code>
- </pre>
+ <div>
+ <pre>
+ <code>{playerInfoB.code}</code>
+ </pre>
+ </div>
+ <div>
+ <div>
+ {submissionResultStatusToLabel(
+ playerInfoB.submissionResult?.status ?? null,
+ )}{" "}
+ ({playerInfoB.submissionResult?.preliminaryScore ?? "-"})
+ </div>
+ <div>
+ <ol>
+ {playerInfoB.submissionResult?.verificationResults.map(
+ (result, idx) => (
+ <li key={idx}>
+ <div>
+ <div>
+ <ExecStatusIndicatorIcon status={result.status} />{" "}
+ {result.label}
+ </div>
+ <div>
+ {result.stdout}
+ {result.stderr}
+ </div>
+ </div>
+ </li>
+ ),
+ )}
+ </ol>
</div>
</div>
</div>
+ <div className="grid justify-center p-2 bg-slate-300">{problem}</div>
</div>
);
}