diff --git a/backend/terry/handlers/info_handler.py b/backend/terry/handlers/info_handler.py index 8a9473c9..6fc1f405 100644 --- a/backend/terry/handlers/info_handler.py +++ b/backend/terry/handlers/info_handler.py @@ -203,7 +203,10 @@ def patch_submission(submission): del result["output"] result = BaseHandler.format_dates(result) + result["output"] = temp + if "subtasks" in feedback: + result["subtasks"] = feedback["subtasks"] return result diff --git a/format-specs.md b/format-specs.md index 55f8d9df..733af39a 100644 --- a/format-specs.md +++ b/format-specs.md @@ -125,4 +125,12 @@ The checker should print to its standard output a JSON value with _at least_ the - `severity`: a string with one of the following values: `"warning"` - `message`: the message to show to the contestant. +The following field must be present if and only if the problem is scored with subtasks: +- `subtasks`: the subtasks of the task. It is an array with an entry for each subtask. Each entry is an object with _at least_ the following fields: + - `score`: a number indicating the score of the contestant on the subtask. + - `max_score`: a number indicating the maximum score on the subtask. + - `testcases`: an array of numbers, containing the testcases belonging to the subtask. + +Note that is the checker's responsibility to make sure that the information contained in `subtasks` is accurate. + The checker should be very resilient to invalid output files submitted by the contestant. To avoid writing every time the parsing code a Python library is available [here](https://github.com/algorithm-ninja/territoriali-cli/blob/master/terry_cli/parser.py). Note that it's useful only for the `Case #1: ...` output format. diff --git a/frontend/src/contest/submission/FeedbackView.tsx b/frontend/src/contest/submission/FeedbackView.tsx index d228c6cf..b4090d73 100644 --- a/frontend/src/contest/submission/FeedbackView.tsx +++ b/frontend/src/contest/submission/FeedbackView.tsx @@ -59,6 +59,7 @@ export function FeedbackView({ submission, task }: Props) { diff --git a/frontend/src/contest/submission/GridList.css b/frontend/src/contest/submission/GridList.css index 5a072dbe..d2ab689f 100644 --- a/frontend/src/contest/submission/GridList.css +++ b/frontend/src/contest/submission/GridList.css @@ -17,3 +17,9 @@ dl.terry-grid-list > dd { -ms-flex: 1 1 100%; flex: 1 1 100%; } + +dl.terry-grid-list > dd > table { + border-spacing: 10px 0; + border-collapse: separate; + margin-left: -10px; +} diff --git a/frontend/src/contest/submission/ResultView.tsx b/frontend/src/contest/submission/ResultView.tsx index 968c38b7..6353d696 100644 --- a/frontend/src/contest/submission/ResultView.tsx +++ b/frontend/src/contest/submission/ResultView.tsx @@ -1,17 +1,63 @@ import React from "react"; import { Trans } from "@lingui/macro"; -import { Alert } from "src/types/contest"; +import { Alert, Subtask } from "src/types/contest"; type Props = { cases: T[]; alerts: Alert[]; + subtasks?: Subtask[]; renderCase: (c: T, i: number) => React.ReactNode; renderCaseSummary: (c: T, i: number) => React.ReactNode; }; export function ResultView({ - cases, alerts, renderCase, renderCaseSummary, + cases, alerts, subtasks, renderCase, renderCaseSummary, }: Props) { + const renderGridWithSubtasks = (subtasks: Subtask[], cases: T[]) => { + return ( + <> + + + {subtasks.map((s: Subtask, i: number) => ( + + + + + ))} + +
+ Subtask {i + 1} ({s.score}/{s.max_score}) + +
    + {s.testcases.map((i: number, _: number) => ( + // eslint-disable-next-line react/no-array-index-key +
  • + {renderCaseSummary(cases[i], i + 1)} +
  • + ))} +
+
+ + ) + }; + + const renderGridWithoutSubtasks = (cases: T[]) => { + return ( + <> +
    + {cases.map((c: T, i: number) => ( + // eslint-disable-next-line react/no-array-index-key +
  • + {renderCaseSummary(c, i + 1)} +
  • + ))} +
+ + ); + } + + const summary = subtasks ? renderGridWithSubtasks(subtasks, cases) : renderGridWithoutSubtasks(cases); + return ( <>
    @@ -34,14 +80,7 @@ export function ResultView({ :
    -
      - {cases.map((c: T, i: number) => ( - // eslint-disable-next-line react/no-array-index-key -
    • - {renderCaseSummary(c, i + 1)} -
    • - ))} -
    + {summary}
    diff --git a/frontend/src/contest/submission/ValidationView.tsx b/frontend/src/contest/submission/ValidationView.tsx index 85b22fda..68aafbd1 100644 --- a/frontend/src/contest/submission/ValidationView.tsx +++ b/frontend/src/contest/submission/ValidationView.tsx @@ -45,6 +45,7 @@ export function ValidationView({ output }: Props) { diff --git a/frontend/src/types/contest.ts b/frontend/src/types/contest.ts index f867af72..0016c1d5 100644 --- a/frontend/src/types/contest.ts +++ b/frontend/src/types/contest.ts @@ -17,6 +17,12 @@ type FeedbackData = { cases: FeedbackCaseInfo[]; }; +export type Subtask = { + max_score: number; + score: number; + testcases: number[]; +}; + export type Submission = { id: string; date: string; @@ -26,6 +32,7 @@ export type Submission = { input: InputData; output: UploadedOutput; source: UploadedSource; + subtasks: Subtask[]; feedback: FeedbackData; };