elemes/frontend/src/lib/services/evaluators.ts

92 lines
2.7 KiB
TypeScript

import { checkKeyText, missingKeyTextKeys, validateNodes } from '$services/exercise';
import type { LessonContent } from '$types/lesson';
import type { CircuitJSApi } from '$types/circuitjs';
export interface CircuitEvalResult {
pass: boolean;
output: string;
error?: string;
}
export function evaluateCircuitSubmission(
simApi: CircuitJSApi,
circuitText: string,
isHybrid: boolean,
data: LessonContent,
checkAllPassed: () => boolean
): CircuitEvalResult {
const circuitExpected = (isHybrid && data.expected_circuit_output)
? data.expected_circuit_output
: data.expected_output;
let expectedState: any = null;
try {
if (circuitExpected) expectedState = JSON.parse(circuitExpected);
} catch {
return { pass: false, output: '', error: "Format EXPECTED_OUTPUT tidak valid (Harus JSON)." };
}
if (!expectedState) {
return { pass: true, output: "Tidak ada kriteria evaluasi yang ditetapkan." };
}
let { allPassed, messages } = expectedState.nodes
? validateNodes(simApi, expectedState.nodes)
: { allPassed: true, messages: [] as string[] };
const circuitKeyText = (isHybrid && data.key_text_circuit) ? data.key_text_circuit : data.key_text;
if (!checkKeyText(circuitText, circuitKeyText ?? '')) {
allPassed = false;
messages.push(`❌ Komponen wajib belum lengkap (lihat instruksi).`);
}
let finalOutput = messages.join('\n');
if (allPassed && isHybrid) {
finalOutput += '\n✅ Rangkaian benar!';
if (!checkAllPassed()) {
finalOutput += '\n⏳ Selesaikan juga tantangan kode untuk menyelesaikan pelajaran ini.';
}
}
return { pass: allPassed, output: finalOutput };
}
export interface LanguageEvalResult {
isCorrect: boolean;
reason?: 'output-mismatch' | 'keytext-missing';
missingKeys?: string[];
}
export function processLanguageEvaluation(
compileOutput: string,
code: string,
lang: 'c' | 'python',
currentLanguage: string,
cCode: string,
pythonCode: string,
data: LessonContent
): LanguageEvalResult {
if (!data.expected_output && !data.expected_output_python) return { isCorrect: true };
const currentCCode = (currentLanguage === 'c') ? code : cCode;
const currentPythonCode = (currentLanguage === 'python') ? code : pythonCode;
const mergedCode = currentCCode + '\n' + currentPythonCode;
const expected = (lang === 'python' && data.expected_output_python)
? data.expected_output_python
: data.expected_output;
const outputMatches = compileOutput.trim() === (expected ?? '').trim();
if (!outputMatches) {
return { isCorrect: false, reason: 'output-mismatch' };
}
const missingKeys = missingKeyTextKeys(mergedCode, data.key_text ?? '');
if (missingKeys.length > 0) {
return { isCorrect: false, reason: 'keytext-missing', missingKeys };
}
return { isCorrect: true };
}