NEET Score Checker(By neetandclear.in)

Check NEET OMR score with a visual report, supports dark mode and dragging UI box.

// ==UserScript==
// @name         NEET Score Checker(By neetandclear.in)
// @namespace    http://tampermonkey.net/
// @version      2025-06-05
// @description  Check NEET OMR score with a visual report, supports dark mode and dragging UI box.
// @author       Manab Bala
// @match        https://examinationservices.nic.in/NEET2025/OMRChallenge/ChallangeOMR.aspx
// @icon         https://www.neetandclear.in/favicon.ico
// @grant        none
// ==/UserScript==

(function () {
    'use strict';

    const response = [
    ];

    // Select all spans with id ending in 'Answer'
    const answerSpans = document.querySelectorAll('span[id$="Answer"]');

    // Example: Log all values
    answerSpans.forEach(span => {
        response.push(span.textContent);
    });

    const answerKey_45 = ['2', '2', '2', '4', '2', '2', '4', '4', '1', '1', '4', '1', '3', '3', '2', '2', '4', '2', '3', '1', '4', '2', '2', '3', '3', '3', '1', '4', '2', '3', '1', '2', '3', '2', '2', '2', '3', '1', '3', '2', '2', '3', '3', '4', '2', '4', '2', '2', '1', '1', '3', '3', '2', '4', '1', '4', '2', '4', '4', '4', '3', '2', '1,2', '1', '1', '2', '3', '2', '2', '3', '3', '1', '3', '1', '4', '1', '1', '2', '3', '3', '2', '2', '2', '1', '1', '3', '1', '4', '1', '4', '2', '2', '1', '4', '1', '1', '1', '1', '3', '3', '4', '2', '3', '4', '4', '3', '4', '4', '2', '1', '1', '1', '2', '4', '3', '1', '3', '1', '3', '4', '4', '2', '4', '4', '2', '4', '3', '1', '2', '2', '4', '2', '2', '3', '2', '1', '3', '1', '4', '1', '1', '1', '3', '1', '3', '1', '2', '4', '3', '4', '1', '1', '1', '3', '3', '4', '2', '1', '2', '2', '2', '2', '1', '2', '2', '2', '2', '2', '4', '3', '4', '1', '1', '3', '3', '2', '2', '1', '4', '2']
    const answerKey_46 = ['2', '2', '4', '2', '2', '1', '4', '1', '2', '2', '2', '3', '1', '1', '3', '3', '4', '3', '1', '1', '3', '1', '1', '1', '4', '1', '1', '1', '2', '2', '1', '1', '1', '1', '2', '4', '3', '3', '1', '1', '4', '2', '2', '3', '4', '2', '2', '2', '1', '1', '1', '2', '3', '2', '1', '1,4', '1', '3', '3', '3', '3', '1', '2', '3', '2', '1', '4', '4', '4', '4', '2', '4', '4', '3', '2', '3', '1', '3', '1', '4', '4', '4', '1', '1', '1', '4', '4', '4', '4', '2', '4', '3', '4', '1', '3', '4', '3', '2', '1', '2', '2', '1', '3', '3', '4', '4', '1', '1', '1', '2', '1', '4', '1', '1', '1', '4', '2', '2', '3', '2', '4', '4', '4', '4', '3', '4', '2', '1', '4', '2', '1', '4', '1', '4', '1', '3', '2', '1', '2', '3', '3', '1', '3', '4', '1', '1', '3', '4', '3', '4', '2', '2', '4', '4', '4', '2', '1', '3', '3', '4', '3', '3', '4', '2', '3', '4', '1', '1', '3', '2', '1', '3', '4', '2', '4', '1', '1', '1', '1', '2']
    const answerKey_47 = ['3', '2', '3', '3', '4', '2', '3', '3', '3', '2', '3', '4', '1', '1', '4', '3', '2', '4', '1', '3', '4', '3', '1', '4', '3', '1', '3', '1', '4', '2', '2', '1', '4', '1', '3', '3', '3', '3', '4', '4', '2', '3', '4', '3', '4', '4', '3', '1', '3', '2', '2', '3', '1', '3', '2', '2', '2', '2,3', '1', '4', '2', '4', '3', '4', '1', '4', '3', '1', '3', '4', '4', '2', '3', '2', '4', '1', '1', '3', '1', '1', '2', '3', '2', '3', '2', '2', '2', '4', '4', '3', '1', '3', '2', '4', '2', '2', '4', '4', '2', '2', '1', '3', '4', '2', '3', '4', '2', '4', '2', '1', '2', '3', '2', '1', '2', '4', '2', '3', '4', '3', '3', '3', '3', '1', '3', '2', '3', '3', '3', '4', '2', '3', '2', '1', '1', '2', '1', '3', '4', '3', '2', '3', '1', '1', '2', '1', '4', '1', '3', '2', '1', '2', '3', '4', '1', '4', '1', '4', '2', '1', '3', '3', '1', '3', '2', '3', '1', '4', '4', '2', '4', '2', '4', '1', '3', '3', '2', '2', '1', '3']
    const answerKey_48 = ['1', '4', '3', '1', '4', '4', '1', '4', '2', '1', '4', '4', '4', '2', '4', '4', '2', '2', '4', '4', '4', '3', '4', '2', '2', '1', '1', '4', '1', '2', '1', '2', '3', '1', '1', '1', '4', '3', '4', '3', '4', '3', '1', '3', '4', '4', '1', '2', '3', '4', '3,4', '1', '3', '3', '1', '1', '1', '2', '3', '2', '4', '3', '4', '3', '4', '1', '1', '2', '1', '4', '4', '1', '2', '3', '3', '2', '3', '4', '1', '4', '3', '3', '3', '4', '2', '2', '4', '2', '3', '4', '1', '1', '1', '1', '4', '4', '3', '1', '2', '4', '3', '3', '3', '1', '1', '2', '4', '4', '4', '3', '2', '2', '1', '4', '3', '4', '1', '4', '3', '1', '4', '1', '4', '3', '2', '2', '2', '2', '4', '4', '2', '3', '3', '4', '3', '3', '2', '4', '1', '4', '4', '3', '3', '2', '2', '3', '2', '4', '3', '4', '4', '2', '1', '2', '3', '2', '4', '3', '3', '3', '3', '1', '2', '4', '1', '3', '3', '4', '3', '2', '4', '1', '3', '1', '1', '4', '2', '4', '2', '3']


    const panel = document.createElement("div");
    panel.innerHTML = `
        <style>
            #neetScorePanel {
                position: fixed;
                top: 80px;
                right: 20px;
                background-color: #222;
                color: #fff;
                padding: 16px;
                border-radius: 10px;
                box-shadow: 0 0 10px rgba(0,0,0,0.5);
                z-index: 9999;
                font-family: sans-serif;
                width: 300px;
                cursor: move;
                user-select: none;
            }
            #neetScorePanel h2 {
                margin-top: 0;
                font-size: 18px;
                text-align: center;
            }
            #neetScorePanel select {
                margin: 8px 0;
                padding: 5px;
                width: 100%;
                background-color: #333; /* Dark background */
                color: #fff;            /* Light text */
                border: 1px solid #666;
                border-radius: 5px;
                appearance: none;       /* Optional: remove default arrow */
            }

            #neetScorePanel option {
                background-color: #333;
                color: #fff;
            }
            #neetScorePanel table {
                width: 100%;
                border-collapse: collapse;
                margin-top: 10px;
                font-size: 14px;
            }
            #neetScorePanel th, #neetScorePanel td {
                padding: 5px;
                border: 1px solid #666;
                text-align: center;
            }
        </style>
        <div id="neetScorePanel">
            <h2>NEET Score Checker</h2>
            <label for="keySelect">Booklet Code:</label>
            <select id="keySelect" >
                <option value="45">Code 45</option>
                <option value="46">Code 46</option>
                <option value="47">Code 47</option>
                <option value="48">Code 48</option>
            </select>
            <div id="scoreTableContainer"></div>
        </div>
    `;
    document.body.appendChild(panel);

    const keyMap = {
        45: answerKey_45,
        46: answerKey_46,
        47: answerKey_47,
        48: answerKey_48
    };

    function getSubject(index) {
        if (index >= 0 && index < 45) return "Physics";
        if (index >= 45 && index < 90) return "Chemistry";
        return "Biology";
    }

    function calculateAndRenderReport(selectedKey) {
        const answerKey = keyMap[selectedKey];
        console.log("response:", response);
        console.log("answerKey", answerKey)
        const subjects = {
            Physics: { correct: 0, wrong: 0, skipped: 0 },
            Chemistry: { correct: 0, wrong: 0, skipped: 0 },
            Biology: { correct: 0, wrong: 0, skipped: 0 }
        };
        const subjectScore = { Physics: 0, Chemistry: 0, Biology: 0 };

        response.forEach((userAns, i) => {
            const subject = getSubject(i);
            const correctAns = answerKey[i];
            if (userAns === "-") {
                subjects[subject].skipped++;
                return;
            }

            const correctOptions = new Set(correctAns.split(","));
            if (correctOptions.has(userAns)) {
                subjects[subject].correct++;
                subjectScore[subject] += 4;
            } else {
                subjects[subject].wrong++;
                subjectScore[subject] -= 1;
            }
        });

        const report = {
            Physics: { ...subjects.Physics, score: subjectScore.Physics },
            Chemistry: { ...subjects.Chemistry, score: subjectScore.Chemistry },
            Biology: { ...subjects.Biology, score: subjectScore.Biology },
            Total: {
                correct: Object.values(subjects).reduce((sum, s) => sum + s.correct, 0),
                wrong: Object.values(subjects).reduce((sum, s) => sum + s.wrong, 0),
                skipped: Object.values(subjects).reduce((sum, s) => sum + s.skipped, 0),
                score: Object.values(subjectScore).reduce((sum, s) => sum + s, 0)
            }
        };

        const tableHTML = `
            <table>
                <thead>
                    <tr><th>Subject</th><th>✔️</th><th>❌</th><th>⏭️</th><th>Score</th></tr>
                </thead>
                <tbody>
                    <tr><td>Physics</td><td>${report.Physics.correct}</td><td>${report.Physics.wrong}</td><td>${report.Physics.skipped}</td><td>${report.Physics.score}</td></tr>
                    <tr><td>Chemistry</td><td>${report.Chemistry.correct}</td><td>${report.Chemistry.wrong}</td><td>${report.Chemistry.skipped}</td><td>${report.Chemistry.score}</td></tr>
                    <tr><td>Biology</td><td>${report.Biology.correct}</td><td>${report.Biology.wrong}</td><td>${report.Biology.skipped}</td><td>${report.Biology.score}</td></tr>
                    <tr><td>Total</td><td>${report.Total.correct}</td><td>${report.Total.wrong}</td><td>${report.Total.skipped}</td><td>${report.Total.score}</td></tr>
                </tbody>
            </table>
        `;
        document.getElementById("scoreTableContainer").innerHTML = tableHTML;
    }

    document.getElementById("keySelect").addEventListener("change", function () {
        calculateAndRenderReport(this.value);
    });
    calculateAndRenderReport("45");

    // Make panel draggable
    const panelDiv = document.getElementById("neetScorePanel");
    let isDragging = false;
    let offsetX, offsetY;

    panelDiv.addEventListener("mousedown", function (e) {
        isDragging = true;
        offsetX = e.clientX - panelDiv.offsetLeft;
        offsetY = e.clientY - panelDiv.offsetTop;
    });

    document.addEventListener("mousemove", function (e) {
        if (isDragging) {
            panelDiv.style.left = `${e.clientX - offsetX}px`;
            panelDiv.style.top = `${e.clientY - offsetY}px`;
        }
    });

    document.addEventListener("mouseup", function () {
        isDragging = false;
    });
})();