Skip to content

Commit

Permalink
feat: display dynamic problem score in competition overview
Browse files Browse the repository at this point in the history
  • Loading branch information
dreamerblue committed Dec 16, 2023
1 parent a67ac23 commit 3ba95fe
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 4 deletions.
10 changes: 10 additions & 0 deletions src/@types/models.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -675,3 +675,13 @@ interface ICompetitionSessionStatus {
role: number;
};
}

interface ICompetitionProblemResultStats {
[key: number]: {
accepted: number;
submitted: number;
selfTries: number;
selfAccepted: boolean;
selfAcceptedTime: Date | null;
};
}
2 changes: 1 addition & 1 deletion src/common
69 changes: 66 additions & 3 deletions src/pages/competitions/$id/overview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import tracker from '@/utils/tracker';
import GeneralFormModal from '@/components/GeneralFormModal';
import Explanation from '@/components/Explanation';
import { getReadableVarScoreExpression } from '@/utils/competition';
import { compileVarScoreExpression } from '@/common/utils/competition';

export interface Props extends ReduxProps {
id: number;
Expand All @@ -38,7 +39,7 @@ export interface Props extends ReduxProps {
problemsLoading: boolean;
problems: IFullList<ICompetitionProblem>;
userProblemResultStats: IUserProblemResultStats;
competitionProblemResultStats: IContestProblemResultStats;
competitionProblemResultStats: ICompetitionProblemResultStats;
notifications: ICompetitionNotification[];
notificationsLoading: boolean;
questions: ICompetitionQuestion[];
Expand Down Expand Up @@ -150,6 +151,48 @@ class CompetitionOverview extends React.Component<Props, State> {
];
};

evalVarScoreExpression = (
score: number | null,
varScoreExpression: string,
detail: ICompetition,
problemIndex: number,
tries = 0,
acceptedTime?: Date | string,
): number | null => {
if (typeof score !== 'number') {
return null;
}
if (!varScoreExpression) {
return score;
}

try {
const currentTime = Date.now() - ((window as any)._t_diff || 0);
const startTime = toLongTs(detail.startAt);
const elapsedMs = (acceptedTime ? toLongTs(acceptedTime) : currentTime) - startTime;
const expression = compileVarScoreExpression(varScoreExpression, {
score,
problemIndex,
elapsedTime: {
h: Math.floor(elapsedMs / 1000 / 60 / 60),
min: Math.floor(elapsedMs / 1000 / 60),
s: Math.floor(elapsedMs / 1000),
},
tries,
});
try {
// eslint-disable-next-line no-eval
return eval(expression);
} catch (e) {
console.error('failed to eval var score expression', varScoreExpression, expression, e);
return null;
}
} catch (e) {
console.error('unknown error while evaling var score expression', e);
return null;
}
};

render() {
const {
id,
Expand Down Expand Up @@ -301,11 +344,31 @@ class CompetitionOverview extends React.Component<Props, State> {
key="Score"
render={(text, record: ICompetitionProblem, index) => (
<div>
{record.score ?? '-'}
<span
className={
competitionProblemResultStats[record.problemId]?.selfAccepted
? 'text-success'
: ''
}
>
{this.evalVarScoreExpression(
record.score,
record.varScoreExpression,
detail,
index,
competitionProblemResultStats[record.problemId]?.selfTries,
competitionProblemResultStats[record.problemId]?.selfAcceptedTime,
) ?? '-'}
</span>
{typeof record.score === 'number' && (
<Explanation className="ml-sm-md">
<p className="mb-sm">Base Score: {record.score}</p>
{!!record.varScoreExpression && <p>Score Rule: {getReadableVarScoreExpression(record.varScoreExpression)}</p>}
{!!record.varScoreExpression && (
<p>
Score Rule:{' '}
{getReadableVarScoreExpression(record.varScoreExpression)}
</p>
)}
</Explanation>
)}
</div>
Expand Down

0 comments on commit 3ba95fe

Please sign in to comment.