CoolFace
Apppublic

sanket3280/code-execution

sourceHugging Faceupdated 10mo agoView on Hugging Face
0likes
answerVerifiers.js300 linesDownload Raw Back to utils
1/**2 * Answer Verification System3 * Handles problems with multiple valid answers4 */5 6class AnswerVerifier {7  8  /**9   * Verify palindrome problems (e.g., Longest Palindromic Substring)10   */11  static verifyPalindrome(input, userOutput, metadata = {}) {12    try {13      // Parse input if it's JSON14      let inputStr = String(input);15      if (inputStr.startsWith('{')) {16        try {17          const parsed = JSON.parse(inputStr);18          inputStr = parsed.s || parsed.str || parsed.string || inputStr;19        } catch (e) {20          // Not JSON, use as is21        }22      }23      24      const outputStr = String(userOutput).trim();25      26      // 1. Check if substring27      if (!inputStr.includes(outputStr)) {28        return { 29          valid: false, 30          reason: `"${outputStr}" is not a substring of input "${inputStr}"` 31        };32      }33      34      // 2. Check if palindrome35      const reversed = outputStr.split('').reverse().join('');36      if (outputStr !== reversed) {37        return { 38          valid: false, 39          reason: `"${outputStr}" is not a palindrome` 40        };41      }42      43      // 3. Check if longest (if maxLength provided)44      if (metadata.maxLength !== undefined) {45        if (outputStr.length !== metadata.maxLength) {46          return { 47            valid: false, 48            reason: `Length ${outputStr.length}, expected ${metadata.maxLength}` 49          };50        }51      } else {52        // Calculate longest palindrome length53        const maxLen = this.findLongestPalindromeLength(inputStr);54        if (outputStr.length !== maxLen) {55          return { 56            valid: false, 57            reason: `Length ${outputStr.length}, expected ${maxLen}` 58          };59        }60      }61      62      // Find all valid palindromes of the same length63      const allValidPalindromes = this.findAllPalindromesOfLength(inputStr, outputStr.length);64      65      return { 66        valid: true, 67        reason: "Multiple valid palindrome answers accepted",68        allValidOutputs: allValidPalindromes.length > 1 ? allValidPalindromes : null69      };70      71    } catch (error) {72      return { 73        valid: false, 74        reason: `Verification error: ${error.message}` 75      };76    }77  }78  79  /**80   * Find longest palindrome length in string81   */82  static findLongestPalindromeLength(s) {83    if (!s || s.length === 0) return 0;84    85    let maxLen = 0;86    87    const expandAroundCenter = (left, right) => {88      while (left >= 0 && right < s.length && s[left] === s[right]) {89        left--;90        right++;91      }92      return right - left - 1;93    };94    95    for (let i = 0; i < s.length; i++) {96      const len1 = expandAroundCenter(i, i);97      const len2 = expandAroundCenter(i, i + 1);98      maxLen = Math.max(maxLen, len1, len2);99    }100    101    return maxLen;102  }103  104  /**105   * Find all palindromes of a specific length in string106   */107  static findAllPalindromesOfLength(s, targetLength) {108    if (!s || s.length === 0 || targetLength <= 0) return [];109    110    const palindromes = new Set();111    112    const expandAroundCenter = (left, right) => {113      while (left >= 0 && right < s.length && s[left] === s[right]) {114        const len = right - left + 1;115        if (len === targetLength) {116          palindromes.add(s.substring(left, right + 1));117        }118        left--;119        right++;120      }121    };122    123    for (let i = 0; i < s.length; i++) {124      expandAroundCenter(i, i);     // odd length125      expandAroundCenter(i, i + 1); // even length126    }127    128    return Array.from(palindromes);129  }130  131  /**132   * Verify array problems where order doesn't matter133   */134  static verifyArrayAnyOrder(expected, userOutput) {135    try {136      // Parse if strings137      const exp = typeof expected === 'string' ? JSON.parse(expected) : expected;138      const user = typeof userOutput === 'string' ? JSON.parse(userOutput) : userOutput;139      140      // Check if arrays141      if (!Array.isArray(exp) || !Array.isArray(user)) {142        return { 143          valid: false, 144          reason: "Expected array output" 145        };146      }147      148      // Check length149      if (exp.length !== user.length) {150        return { 151          valid: false, 152          reason: `Array length ${user.length}, expected ${exp.length}` 153        };154      }155      156      // Sort and compare157      const sortedExp = JSON.stringify([...exp].sort());158      const sortedUser = JSON.stringify([...user].sort());159      160      if (sortedExp === sortedUser) {161        return { 162          valid: true, 163          reason: "Arrays match (order independent)",164          allValidOutputs: exp.length > 1 ? exp : null165        };166      }167      168      return { 169        valid: false, 170        reason: "Array elements don't match" 171      };172      173    } catch (error) {174      return { 175        valid: false, 176        reason: `Verification error: ${error.message}` 177      };178    }179  }180  181  /**182   * Verify if user output is one of the valid outputs in expected array183   */184  static verifyArrayMembership(expected, userOutput) {185    try {186      // Parse expected if string187      const expectedArray = typeof expected === 'string' ? JSON.parse(expected) : expected;188      189      // Check if expected is array190      if (!Array.isArray(expectedArray)) {191        return { 192          valid: false, 193          reason: "Expected should be an array of valid outputs" 194        };195      }196      197      // Normalize user output198      let userStr = String(userOutput).trim();199      200      // Try to parse if it looks like JSON201      let userValue = userStr;202      try {203        if (userStr.startsWith('[') || userStr.startsWith('{') || userStr.startsWith('"')) {204          userValue = JSON.parse(userStr);205        }206      } catch (e) {207        // Keep as string208      }209      210      // Check if user output matches any expected output211      const userJson = JSON.stringify(userValue);212      const isValid = expectedArray.some(exp => {213        const expJson = JSON.stringify(exp);214        return expJson === userJson;215      });216      217      if (isValid) {218        return {219          valid: true,220          reason: "Output matches one of the valid answers",221          allValidOutputs: expectedArray222        };223      }224      225      return {226        valid: false,227        reason: `Output not in valid answers. Expected one of: ${expectedArray.slice(0, 3).map(v => JSON.stringify(v)).join(', ')}${expectedArray.length > 3 ? '...' : ''}`228      };229      230    } catch (error) {231      return { 232        valid: false, 233        reason: `Verification error: ${error.message}` 234      };235    }236  }237  238  /**239   * Verify against set of valid outputs240   */241  static verifySetMembership(expectedOutputs, userOutput) {242    try {243      // Normalize244      const userStr = String(userOutput).trim();245      const validOutputs = expectedOutputs.map(o => String(o).trim());246      247      if (validOutputs.includes(userStr)) {248        return { 249          valid: true, 250          reason: "Output matches valid answer",251          matchedOutput: userStr,252          allValidOutputs: validOutputs253        };254      }255      256      return { 257        valid: false, 258        reason: "Output doesn't match any valid answer",259        validOptions: validOutputs.slice(0, 3) // Show first 3260      };261      262    } catch (error) {263      return { 264        valid: false, 265        reason: `Verification error: ${error.message}` 266      };267    }268  }269  270  /**271   * Main verification dispatcher272   */273  static verify(verifierType, input, userOutput, expected, metadata = {}) {274    switch (verifierType) {275      case 'palindrome':276        return this.verifyPalindrome(input, userOutput, metadata);277        278      case 'array_any_order':279        return this.verifyArrayAnyOrder(expected, userOutput);280        281      case 'array_membership':282        return this.verifyArrayMembership(expected, userOutput);283        284      case 'set_membership': {285        const expectedOutputs = metadata.expectedOutputs || [expected];286        return this.verifySetMembership(expectedOutputs, userOutput);287      }288        289      default:290        // Fallback to strict comparison291        return {292          valid: String(userOutput).trim() === String(expected).trim(),293          reason: "Exact match comparison"294        };295    }296  }297}298 299module.exports = AnswerVerifier;300