aboutsummaryrefslogtreecommitdiffhomepage
path: root/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'frontend')
-rw-r--r--frontend/app/.server/api/schema.d.ts22
-rw-r--r--frontend/app/components/GolfPlayApp.client.tsx82
-rw-r--r--frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx13
-rw-r--r--frontend/app/components/GolfWatchApp.client.tsx8
4 files changed, 97 insertions, 28 deletions
diff --git a/frontend/app/.server/api/schema.d.ts b/frontend/app/.server/api/schema.d.ts
index 5b37081..7fd612e 100644
--- a/frontend/app/.server/api/schema.d.ts
+++ b/frontend/app/.server/api/schema.d.ts
@@ -130,7 +130,7 @@ export interface components {
description: string;
};
GamePlayerMessage: components["schemas"]["GamePlayerMessageS2C"] | components["schemas"]["GamePlayerMessageC2S"];
- GamePlayerMessageS2C: components["schemas"]["GamePlayerMessageS2CStart"] | components["schemas"]["GamePlayerMessageS2CExecResult"];
+ GamePlayerMessageS2C: components["schemas"]["GamePlayerMessageS2CStart"] | components["schemas"]["GamePlayerMessageS2CExecResult"] | components["schemas"]["GamePlayerMessageS2CSubmitResult"];
GamePlayerMessageS2CStart: {
/** @constant */
type: "player:s2c:start";
@@ -146,11 +146,29 @@ export interface components {
data: components["schemas"]["GamePlayerMessageS2CExecResultPayload"];
};
GamePlayerMessageS2CExecResultPayload: {
+ /** @example 1 */
+ testcase_id: number | null;
/**
* @example success
* @enum {string}
*/
- status: "success" | "failure" | "timeout" | "internal_error" | "compile_error" | "wrong_answer";
+ status: "success" | "wrong_answer" | "timeout" | "runtime_error" | "internal_error" | "compile_error";
+ /** @example Hello, world! */
+ stdout: string;
+ /** @example */
+ stderr: string;
+ };
+ GamePlayerMessageS2CSubmitResult: {
+ /** @constant */
+ type: "player:s2c:submitresult";
+ data: components["schemas"]["GamePlayerMessageS2CSubmitResultPayload"];
+ };
+ GamePlayerMessageS2CSubmitResultPayload: {
+ /**
+ * @example success
+ * @enum {string}
+ */
+ status: "success" | "wrong_answer" | "timeout" | "runtime_error" | "internal_error" | "compile_error";
/** @example 100 */
score: number | null;
};
diff --git a/frontend/app/components/GolfPlayApp.client.tsx b/frontend/app/components/GolfPlayApp.client.tsx
index ef3a229..dbc8c1b 100644
--- a/frontend/app/components/GolfPlayApp.client.tsx
+++ b/frontend/app/components/GolfPlayApp.client.tsx
@@ -2,6 +2,7 @@ import { useEffect, useState } from "react";
import { useDebouncedCallback } from "use-debounce";
import type { components } from "../.server/api/schema";
import useWebSocket, { ReadyState } from "../hooks/useWebSocket";
+import type { PlayerInfo } from "../models/PlayerInfo";
import GolfPlayAppConnecting from "./GolfPlayApps/GolfPlayAppConnecting";
import GolfPlayAppFinished from "./GolfPlayApps/GolfPlayAppFinished";
import GolfPlayAppGaming from "./GolfPlayApps/GolfPlayAppGaming";
@@ -73,9 +74,21 @@ export default function GolfPlayApp({
}
}, [gameState, startedAt, game.duration_seconds]);
- const [currentScore, setCurrentScore] = useState<number | null>(null);
-
- const [lastExecStatus, setLastExecStatus] = useState<string | null>(null);
+ const [playerInfo, setPlayerInfo] = useState<Omit<PlayerInfo, "code">>({
+ displayName: player.display_name,
+ iconPath: player.icon_path ?? null,
+ score: null,
+ submitResult: {
+ status: "waiting_submission",
+ execResults: game.exec_steps.map((r) => ({
+ testcase_id: r.testcase_id,
+ status: "waiting_submission",
+ label: r.label,
+ stdout: "",
+ stderr: "",
+ })),
+ },
+ });
const onCodeChange = useDebouncedCallback((code: string) => {
console.log("player:c2s:code");
@@ -94,6 +107,18 @@ export default function GolfPlayApp({
type: "player:c2s:submit",
data: { code },
});
+ setPlayerInfo((prev) => ({
+ ...prev,
+ submitResult: {
+ status: "running",
+ execResults: prev.submitResult.execResults.map((r) => ({
+ ...r,
+ status: "running",
+ stdout: "",
+ stderr: "",
+ })),
+ },
+ }));
}, 1000);
if (readyState === ReadyState.UNINSTANTIATED) {
@@ -123,14 +148,46 @@ export default function GolfPlayApp({
setGameState("starting");
}
} else if (lastJsonMessage.type === "player:s2c:execresult") {
+ const { testcase_id, status, stdout, stderr } = lastJsonMessage.data;
+ setPlayerInfo((prev) => {
+ const ret = { ...prev };
+ ret.submitResult = {
+ ...prev.submitResult,
+ execResults: prev.submitResult.execResults.map((r) =>
+ r.testcase_id === testcase_id && r.status === "running"
+ ? {
+ ...r,
+ status,
+ stdout,
+ stderr,
+ }
+ : r,
+ ),
+ };
+ return ret;
+ });
+ } else if (lastJsonMessage.type === "player:s2c:submitresult") {
const { status, score } = lastJsonMessage.data;
- if (
- score !== null &&
- (currentScore === null || score < currentScore)
- ) {
- setCurrentScore(score);
- }
- setLastExecStatus(status);
+ setPlayerInfo((prev) => {
+ const ret = { ...prev };
+ ret.submitResult = {
+ ...prev.submitResult,
+ status,
+ };
+ if (status === "success") {
+ if (score) {
+ if (ret.score === null || score < ret.score) {
+ ret.score = score;
+ }
+ }
+ } else {
+ ret.submitResult.execResults = prev.submitResult.execResults.map(
+ (r) =>
+ r.status === "running" ? { ...r, status: "canceled" } : r,
+ );
+ }
+ return ret;
+ });
}
} else {
if (game.started_at) {
@@ -165,7 +222,6 @@ export default function GolfPlayApp({
lastJsonMessage,
readyState,
gameState,
- currentScore,
]);
if (gameState === "connecting") {
@@ -178,13 +234,11 @@ export default function GolfPlayApp({
return (
<GolfPlayAppGaming
gameDisplayName={game.display_name}
- playerDisplayName={player.display_name}
+ playerInfo={playerInfo}
problemTitle={game.problem.title}
problemDescription={game.problem.description}
onCodeChange={onCodeChange}
onCodeSubmit={onCodeSubmit}
- currentScore={currentScore}
- lastExecStatus={lastExecStatus}
/>
);
} else if (gameState === "finished") {
diff --git a/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx
index 03acf5a..08490a6 100644
--- a/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx
+++ b/frontend/app/components/GolfPlayApps/GolfPlayAppGaming.tsx
@@ -1,28 +1,25 @@
import { Link } from "@remix-run/react";
import React, { useRef } from "react";
import SubmitButton from "../../components/SubmitButton";
+import type { PlayerInfo } from "../../models/PlayerInfo";
import BorderedContainer from "../BorderedContainer";
type Props = {
gameDisplayName: string;
- playerDisplayName: string;
+ playerInfo: Omit<PlayerInfo, "code">;
problemTitle: string;
problemDescription: string;
onCodeChange: (code: string) => void;
onCodeSubmit: (code: string) => void;
- currentScore: number | null;
- lastExecStatus: string | null;
};
export default function GolfPlayAppGaming({
gameDisplayName,
- playerDisplayName,
+ playerInfo,
problemTitle,
problemDescription,
onCodeChange,
onCodeSubmit,
- currentScore,
- lastExecStatus,
}: Props) {
const textareaRef = useRef<HTMLTextAreaElement>(null);
@@ -45,7 +42,7 @@ export default function GolfPlayAppGaming({
</div>
<div>
<Link to={"/dashboard"} className="font-bold text-xl">
- {playerDisplayName}
+ {playerInfo.displayName}
</Link>
</div>
</div>
@@ -69,7 +66,7 @@ export default function GolfPlayAppGaming({
<SubmitButton onClick={handleSubmitButtonClick}>提出</SubmitButton>
<div className="mb-2 mt-auto">
<div className="font-semibold text-green-500">
- Score: {currentScore ?? "-"} ({lastExecStatus ?? "-"})
+ Score: {playerInfo.score ?? "-"}
</div>
</div>
</div>
diff --git a/frontend/app/components/GolfWatchApp.client.tsx b/frontend/app/components/GolfWatchApp.client.tsx
index 7f582c9..9d3f752 100644
--- a/frontend/app/components/GolfWatchApp.client.tsx
+++ b/frontend/app/components/GolfWatchApp.client.tsx
@@ -161,8 +161,8 @@ export default function GolfWatchApp({
setter((prev) => {
const ret = { ...prev };
ret.submitResult = {
- ...ret.submitResult,
- execResults: ret.submitResult.execResults.map((r) =>
+ ...prev.submitResult,
+ execResults: prev.submitResult.execResults.map((r) =>
r.testcase_id === testcase_id && r.status === "running"
? {
...r,
@@ -182,7 +182,7 @@ export default function GolfWatchApp({
setter((prev) => {
const ret = { ...prev };
ret.submitResult = {
- ...ret.submitResult,
+ ...prev.submitResult,
status,
};
if (status === "success") {
@@ -192,7 +192,7 @@ export default function GolfWatchApp({
}
}
} else {
- ret.submitResult.execResults = ret.submitResult.execResults.map(
+ ret.submitResult.execResults = prev.submitResult.execResults.map(
(r) =>
r.status === "running" ? { ...r, status: "canceled" } : r,
);