50 lines
1.6 KiB
TypeScript
50 lines
1.6 KiB
TypeScript
/**
|
|
* Pure helper functions for exercise evaluation.
|
|
*/
|
|
|
|
import type { CircuitJSApi } from '$types/circuitjs';
|
|
|
|
/** Return key_text keywords (one per line) that are missing from the code. */
|
|
export function missingKeyTextKeys(code: string, keyText: string): string[] {
|
|
if (!keyText.trim()) return [];
|
|
const keys = keyText.split('\n').map(k => k.trim()).filter(k => k.length > 0);
|
|
return keys.filter(key => !code.includes(key));
|
|
}
|
|
|
|
/** Check if code contains all required key_text keywords (one per line). */
|
|
export function checkKeyText(code: string, keyText: string): boolean {
|
|
return missingKeyTextKeys(code, keyText).length === 0;
|
|
}
|
|
|
|
export interface NodeResult {
|
|
passed: boolean;
|
|
message: string;
|
|
}
|
|
|
|
/** Validate circuit node voltages against expected state. */
|
|
export function validateNodes(
|
|
simApi: CircuitJSApi,
|
|
nodes: Record<string, { voltage: number; tolerance?: number }>
|
|
): { allPassed: boolean; messages: string[] } {
|
|
let allPassed = true;
|
|
const messages: string[] = [];
|
|
|
|
for (const [nodeName, criteria] of Object.entries(nodes)) {
|
|
const actualV = simApi.getNodeVoltage(nodeName);
|
|
if (actualV === undefined || actualV === null) {
|
|
allPassed = false;
|
|
messages.push(`❌ Node '${nodeName}' tidak ditemukan.`);
|
|
continue;
|
|
}
|
|
const tol = criteria.tolerance || 0.1;
|
|
if (Math.abs(actualV - criteria.voltage) <= tol) {
|
|
messages.push(`✅ Node '${nodeName}': Tegangan ${actualV.toFixed(2)}V (Sesuai)`);
|
|
} else {
|
|
allPassed = false;
|
|
messages.push(`❌ Node '${nodeName}': Tegangan ${actualV.toFixed(2)}V (Harusnya ~${criteria.voltage}V)`);
|
|
}
|
|
}
|
|
|
|
return { allPassed, messages };
|
|
}
|