Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions app/(api)/_actions/logic/applyDiagnosticAlpha.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,35 @@ import checkMatches from '@actions/logic/checkMatches';
export default async function applyDiagnosticAlpha(options: {
alpha: number;
judgeToTeam: JudgeToTeam[];
}): Promise<{ ok: boolean; body: JudgeToTeam[] | null; error: string | null }> {
}): Promise<{
ok: boolean;
body: JudgeToTeam[] | null;
error: string | null;
message?: string;
}> {
const existing = await GetManySubmissions();
if (existing.ok && existing.body && existing.body.length > 0) {
const teamsRes = await GetManyTeams();
if (!teamsRes.ok) {
return {
ok: false,
body: null,
error:
'Submissions collection is not empty. Please clear before applying diagnostics.',
error: `GetManyTeams error: ${teamsRes.error}`,
};
}
const teamsRes = await GetManyTeams();
if (!teamsRes.ok) {
const teams = teamsRes.body;
const existingCount = existing.ok && existing.body ? existing.body.length : 0;
const maxRounds = 4;
const maxSubmissions = teams.length * maxRounds;
const isSecondRound = existingCount > 0;

if (existingCount >= maxSubmissions) {
return {
ok: false,
body: null,
error: `GetManyTeams error: ${teamsRes.error}`,
error:
'Two rounds have already been completed. Clear submissions to rerun.',
};
}
const teams = teamsRes.body;
const parsedSubmissions = await parseAndReplace(options.judgeToTeam);
if (!checkMatches(parsedSubmissions, teams.length)) {
return {
Expand Down Expand Up @@ -62,5 +72,12 @@ export default async function applyDiagnosticAlpha(options: {
// return { ok: false, body: null, error: res.error };
// }

return { ok: true, body: options.judgeToTeam, error: null };
return {
ok: true,
body: options.judgeToTeam,
error: null,
message: isSecondRound
? 'Second round detected: new pairings were added on top of existing submissions.'
: undefined,
};
}
4 changes: 2 additions & 2 deletions app/(api)/_actions/logic/checkMatches.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ export default function checkMatches(
matches: Submission[],
teamsLength: number
) {
if (matches.length < 3 * teamsLength) return false;
if (matches.length < 2 * teamsLength) return false;

let valid = true;
const mp: Map<string, number> = new Map();
Expand All @@ -18,7 +18,7 @@ export default function checkMatches(
}

mp.forEach((count) => {
if (count !== 3) valid = false;
if (count !== 2) valid = false;
});

return valid;
Expand Down
11 changes: 6 additions & 5 deletions app/(api)/_actions/logic/matchTeams.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@ import matchAllTeams from '@utils/matching/judgesToTeamsAlgorithm';
import parseAndReplace from '@utils/request/parseAndReplace';
import { GetManyTeams } from '@datalib/teams/getTeam';
import { CreateManySubmissions } from '@datalib/submissions/createSubmission';
import { GetManySubmissions } from '@datalib/submissions/getSubmissions';
//import { GetManySubmissions } from '@datalib/submissions/getSubmissions';
import checkMatches from '@actions/logic/checkMatches';

export default async function matchTeams(
options: { alpha: number } = { alpha: 4 }
) {
const submissionsResponse = await GetManySubmissions();
/*const submissionsResponse = await GetManySubmissions();
if (
submissionsResponse.ok &&
submissionsResponse.body &&
Expand All @@ -23,7 +23,7 @@ export default async function matchTeams(
error:
'Submissions collection is not empty. Please clear submissions before matching teams.',
};
}
}*/

// Generate submissions based on judge-team assignments.
const teamsRes = await GetManyTeams();
Expand All @@ -46,10 +46,11 @@ export default async function matchTeams(
}
const res = await CreateManySubmissions(parsedJudgeToTeam);
if (!res.ok) {
console.log(`${res.error}`);
return {
ok: false,
body: null,
error: 'Invalid submissions.',
error: 'Invalid submissions.1',
};
}
// for (const submission of parsedJudgeToTeam) {
Expand All @@ -65,7 +66,7 @@ export default async function matchTeams(
return {
ok: false,
body: null,
error: 'Invalid submissions.',
error: 'Invalid submissions.2',
};
}
return {
Expand Down
28 changes: 28 additions & 0 deletions app/(api)/_datalib/judgeToTeam/getJudgeToTeamPairings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import JudgeToTeam from '@typeDefs/judgeToTeam';
import { getDatabase } from '@utils/mongodb/mongoClient.mjs';
import { HttpError } from '@utils/response/Errors';
import Submission from '@typeDefs/submission';
import { ObjectId, Db } from 'mongodb';

type MongoSubmission = Omit<Submission, 'judge_id' | 'team_id'> & {
judge_id: ObjectId;
team_id: ObjectId;
};

export const GetJudgeToTeamPairings = async () => {
try {
const db = (await getDatabase()) as Db;
const submissions = await db
.collection<MongoSubmission>('submissions')
.find()
.toArray();
const pairings = submissions.map((submission) => ({
judge_id: String(submission.judge_id),
team_id: String(submission.team_id),
}));
return { ok: true, body: pairings as JudgeToTeam[], error: null };
} catch (e) {
const error = e as HttpError;
return { ok: false, body: null, error: error.message };
}
};
24 changes: 21 additions & 3 deletions app/(api)/_utils/matching/judgesToTeamsAlgorithm.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { optedHDTracks, nonHDTracks } from '@data/tracks';

import { GetManyUsers } from '@datalib/users/getUser';
import { GetManyTeams } from '@datalib/teams/getTeam';
import { GetJudgeToTeamPairings } from '@datalib/judgeToTeam/getJudgeToTeamPairings';

interface Judge {
user: User;
Expand Down Expand Up @@ -66,7 +67,7 @@ export default async function matchAllTeams(options?: { alpha?: number }) {
const teamMatchQualities: { [teamId: string]: number[] } = {};
const teamJudgeDomainTypes: { [teamId: string]: string[] } = {};

const rounds = 3;
const rounds = 2;
const ALPHA = options?.alpha ?? 4;
// Fetch all checked in judges.
const judgesResponse = await GetManyUsers({
Expand Down Expand Up @@ -157,6 +158,18 @@ export default async function matchAllTeams(options?: { alpha?: number }) {
.filter((team) => team.tracks.length < rounds)
.map((team) => [team._id ?? '', rounds - team.tracks.length])
);

// Get previous pairings and push it to the judgeToTeam array (so that !duplicateExists is true)
const previousPairings = await GetJudgeToTeamPairings();
if (!previousPairings.ok || !previousPairings.body) {
throw new Error(
`Failed to load existing judge-to-team pairings: ${
previousPairings.error ?? 'Unknown error'
}`
);
}
judgeToTeam.push(...previousPairings.body);

// Main loop: process each team for each round.
for (let domainIndex = 0; domainIndex < rounds; domainIndex++) {
for (const team of modifiedTeams) {
Expand All @@ -170,8 +183,8 @@ export default async function matchAllTeams(options?: { alpha?: number }) {
for (const judge of judgesQueue) {
const duplicateExists = judgeToTeam.some(
(entry) =>
entry.judge_id === judge.user._id?.toString() &&
entry.team_id === team._id?.toString()
String(entry.judge_id) === judge.user._id?.toString() &&
String(entry.team_id) === team._id?.toString()
);
Comment on lines +186 to 188
Copy link

Copilot AI Jan 29, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The String() conversions added here are necessary to handle comparison between previous pairings (which may have ObjectIds from the database) and new entries (which have string IDs). However, there's an inconsistency in the codebase - the same logic in matchingAlgorithm.ts (line 173-174) doesn't use String() conversion. Consider standardizing the approach across both files or document why this difference exists.

Copilot uses AI. Check for mistakes.
if (!duplicateExists) {
selectedJudge = judge;
Expand Down Expand Up @@ -212,6 +225,11 @@ export default async function matchAllTeams(options?: { alpha?: number }) {
shuffleArray(modifiedTeams);
}

// Remove the previous pairings
if (previousPairings.ok && previousPairings.body) {
judgeToTeam.splice(0, previousPairings.body.length);
}

console.log('No. of judgeToTeam:', judgeToTeam.length);

const judgeAssignments = judgesQueue.map((judge) => judge.teamsAssigned);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@ export default function JudgeTeamGrouping() {
setShowSubmissions(true);
setApplyAlphaSuccess(true);
setError('');
if (res.message) {
alert(res.message);
}
} else {
setError(res.error!);
setShowMatching(false);
Expand Down Expand Up @@ -326,14 +329,14 @@ export default function JudgeTeamGrouping() {

return (
<div className={styles.body}>
<div className="flex items-center gap-4">
<h4 style={{ cursor: 'pointer' }}>Error</h4>
{error && (
{error && (
<div className="flex items-center gap-4">
<h4 style={{ cursor: 'pointer' }}>Error</h4>
<div>
<pre style={{ color: 'red' }}>{error}</pre>
</div>
)}
</div>
</div>
)}

{/* Diagnostics inputs */}
<div className="mt-6">
Expand Down