89 lines
2.3 KiB
TypeScript
89 lines
2.3 KiB
TypeScript
import { randomUUID } from "crypto";
|
|
import { getGameTerms, getDistractors } from "@lila/db";
|
|
import type {
|
|
GameRequest,
|
|
GameSession,
|
|
GameQuestion,
|
|
AnswerOption,
|
|
AnswerSubmission,
|
|
AnswerResult,
|
|
} from "@lila/shared";
|
|
import type { GameSessionStore } from "../gameSessionStore/index.js";
|
|
import { NotFoundError } from "../errors/AppError.js";
|
|
import { shuffleArray } from "../lib/utils.js";
|
|
|
|
export const createGameSession = async (
|
|
request: GameRequest,
|
|
store: GameSessionStore,
|
|
): Promise<GameSession> => {
|
|
const terms = await getGameTerms(
|
|
request.source_language,
|
|
request.target_language,
|
|
request.pos,
|
|
request.difficulty,
|
|
request.rounds,
|
|
);
|
|
|
|
const answerKey = new Map<string, number>();
|
|
|
|
const questions: GameQuestion[] = await Promise.all(
|
|
terms.map(async (term) => {
|
|
const distractorTexts = await getDistractors(
|
|
term.termId,
|
|
term.targetText,
|
|
request.target_language,
|
|
request.pos,
|
|
request.difficulty,
|
|
3,
|
|
);
|
|
|
|
const optionTexts = [term.targetText, ...distractorTexts];
|
|
const shuffledTexts = shuffleArray(optionTexts);
|
|
const correctOptionId = shuffledTexts.indexOf(term.targetText);
|
|
|
|
const options: AnswerOption[] = shuffledTexts.map((text, index) => ({
|
|
optionId: index,
|
|
text,
|
|
}));
|
|
|
|
const questionId = randomUUID();
|
|
answerKey.set(questionId, correctOptionId);
|
|
|
|
return {
|
|
questionId,
|
|
prompt: term.sourceText,
|
|
gloss: term.sourceGloss,
|
|
options,
|
|
};
|
|
}),
|
|
);
|
|
|
|
const sessionId = randomUUID();
|
|
await store.create(sessionId, { answers: answerKey });
|
|
|
|
return { sessionId, questions };
|
|
};
|
|
|
|
export const evaluateAnswer = async (
|
|
submission: AnswerSubmission,
|
|
store: GameSessionStore,
|
|
): Promise<AnswerResult> => {
|
|
const session = await store.get(submission.sessionId);
|
|
|
|
if (!session) {
|
|
throw new NotFoundError(`Game session not found: ${submission.sessionId}`);
|
|
}
|
|
|
|
const correctOptionId = session.answers.get(submission.questionId);
|
|
|
|
if (correctOptionId === undefined) {
|
|
throw new NotFoundError(`Question not found: ${submission.questionId}`);
|
|
}
|
|
|
|
return {
|
|
questionId: submission.questionId,
|
|
isCorrect: submission.selectedOptionId === correctOptionId,
|
|
correctOptionId,
|
|
selectedOptionId: submission.selectedOptionId,
|
|
};
|
|
};
|